First my code to make my explanation more clear:
struct Foo {
std::condition_variable cv;
};
static Foo* foo; // dynamically created object
// Thread1
foo->cv.wait(...);
// Thread2
foo->cv.notify();
delete foo; // thread1 might have not left the wait function yet
I am trying to delete a std::condition_variable
while it is in wait
. So from my understanding, I have to notify it first to make it leave it's waiting for routine, and then I can delete it. But after calling notify*
I can't delete it right away, because it might still be in wait because it needs a few cycles. What is a common way to achieve this?
Condition variables are used to wait until a particular condition predicate becomes true. This condition predicate is set by another thread, usually the one that signals the condition.
std::condition_variable The condition_variable class is a synchronization primitive used with a std::mutex to block one or more threads until another thread both modifies a shared variable (the condition) and notifies the condition_variable .
Condition variables are synchronization primitives that enable threads to wait until a particular condition occurs. Condition variables are user-mode objects that cannot be shared across processes. Condition variables enable threads to atomically release a lock and enter the sleeping state.
Condition variables are associated with a mutex because it is the only way it can avoid the race that it is designed to avoid.
You can delete it right away.
Quote from C++ standard:
~ condition_variable();
Requires: There shall be no thread blocked on
*this
. [Note: That is, all threads shall have been notified; they may subsequently block on the lock specified in thewait
. This relaxes the usual rules, which would have required allwait
calls to happen before destruction. Only the notification to unblock thewait
must happen before destruction.
Basically wait
functions are required to perform locking and waiting atomically:
The execution of
notify_one
andnotify_all
shall be atomic. The execution ofwait
,wait_for
, andwait_until
shall be performed in three atomic parts:
- the release of the mutex and entry into the waiting state;
- the unblocking of the
wait
; and- the reacquisition of the lock.
Once notify
wakes a thread, it should be considered "unblocked" and should contest the mutex.
There are similar guarantees about std::mutex
: threads are not required to leave unlock
before mutex is destroyed.
Quote from C++ standard:
The implementation shall provide
lock
andunlock
operations, as described below. For purposes of determining the existence of a data race, these behave as atomic operations. Thelock
andunlock
operations on a single mutex shall appear to occur in a single total order.
Later:
Note: After a thread A has called
unlock()
, releasing a mutex, it is possible for another thread B to lock the same mutex, observe that it is no longer in use, unlock it, and destroy it, before thread A appears to have returned from itsunlock
call.
Such guarantees are required to avoid issues like this, when mutex inside an object is used to protect object reference counter.
Note that this does not guarantee that your implementation has no bugs in this regard. In the past glibc had multiple bugs related to the destruction of synchronization objects, in particular pthread_mutex_unlock
was accessing mutex before returning.
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