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();
}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With