Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

list::empty() multi-threaded behavior?

I have a list that I want different threads to grab elements from. In order to avoid locking the mutex guarding the list when it's empty, I check empty() before locking.

It's okay if the call to list::empty() isn't right 100% of the time. I only want to avoid crashing or disrupting concurrent list::push() and list::pop() calls.

Am I safe to assume VC++ and Gnu GCC will only sometimes get empty() wrong and nothing worse?

if(list.empty() == false){ // unprotected by mutex, okay if incorrect sometimes
    mutex.lock();
    if(list.empty() == false){ // check again while locked to be certain
         element = list.back();
         list.pop_back();
    }
    mutex.unlock();
}
like image 846
Anne Quinn Avatar asked Oct 08 '19 14:10

Anne Quinn


2 Answers

It's okay if the call to list::empty() isn't right 100% of the time.

No, it is not okay. If you check if the list is empty outside of some synchronization mechanism (locking the mutex) then you have a data race. Having a data race means you have undefined behavior. Having undefined behavior means we can no longer reason about the program and any output you get is "correct".

If you value your sanity, you'll take the performance hit and lock the mutex before checking. That said, the list might not even be the correct container for you. If you can let us know exactly what you are doing with it, we might be able to suggest a better container.

like image 151
NathanOliver Avatar answered Sep 18 '22 01:09

NathanOliver


There is a read and a write (most probably to the size member of std::list, if we assume that it's named like that) that are not synchronized in reagard to each other. Imagine that one thread calls empty() (in your outer if()) while the other thread entered the inner if() and executes pop_back(). You are then reading a variable that is, possibly, being modified. This is undefined behaviour.

like image 22
Fureeish Avatar answered Sep 20 '22 01:09

Fureeish