Destroying condition_variable while waiting - c++

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?

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 the wait. This relaxes the usual rules, which
would have required all wait calls to happen before destruction. Only
the notification to unblock the wait must happen before destruction.
Basically wait functions are required to perform locking and waiting atomically:
The execution of notify_one and notify_all shall be atomic. The execution
of wait, wait_for, and wait_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 and unlock operations, as
described below. For purposes of determining the existence of a data
race, these behave as atomic operations. The lock and unlock
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 its unlock 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.

One easy fix: move delete foo into thread 1 after foo->cv.wait(...);.
A better fix would be to change the design to work with std::shared_ptr, no manual delete invocations.

Here is my solution for C++17 (C++11 needs adaptation): notify everybody that we are deleting current instance and make the destructor to wait
Two things to do:
Give to the wait predicate a possibility to exit before object is really deleted
Make the destructor to resync with the lock to make it wait everything is finished (you must be sure all waiting methods are checking the deleting at beginning)
Note: if you have a thread inside this class waiting on the condition_variable, it might be better to join() the thread after notification instead of using the resynchronization lock (see comment in the code)
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <shared_mutex>
using namespace std;
chrono::system_clock::time_point startTime;
struct Foo
{
condition_variable cond;
mutex mutex1;
shared_mutex mutexSafe;
bool deleting = false;
~Foo()
{
deleting = true;
cond.notify_all();
// Will make the destructor to wait all the opened shared_lock are released
unique_lock l(mutexSafe);
}
void waitOnThing(const string& name)
{
// Shared lock to make possible several threads are using the method at the same time
shared_lock lSafe(mutexSafe);
cout << chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - startTime).count()
<< " Thread " << name << " -> waitOnThing()" << endl;
unique_lock l(mutex1);
cond.wait(l, [&]()
{
if (deleting)
{
this_thread::sleep_for(chrono::milliseconds(1000)); // Slow down exit process to show destructor is waiting
return true;
}
return false;
});
cout << chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - startTime).count()
<< " Thread " << name << " unlocked" << endl;
}
};
int main()
{
startTime = chrono::system_clock::now();
Foo* foo = new Foo();
cout << chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - startTime).count()
<< " Starting" << endl;
thread t1([&]() { foo->waitOnThing("t1"); });
thread t2([&]() { foo->waitOnThing("t2"); });
thread t3([&]() { foo->waitOnThing("t3"); });
// Wait a bit to be sure thread started and is waiting
this_thread::sleep_for(chrono::milliseconds(100));
cout << chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - startTime).count()
<< " Deleting foo..." << endl;
delete foo;
cout << chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - startTime).count()
<< " Foo deleted" << endl;
// Avoid demo to crash
t1.join();
t2.join();
t3.join();
}
Result:
0 Starting
4 Thread t2 -> waitOnThing()
4 Thread t1 -> waitOnThing()
4 Thread t3 -> waitOnThing()
100 Deleting foo...
1100 Thread t1 unlocked
2100 Thread t2 unlocked
3100 Thread t3 unlocked
3100 Foo deleted
C++11 :
Class shared_mutex is available only since C++17, if you are using C++11 you can do the same by using a regular unique_lock
and making a vector of mutex (one instance per call to the waiting method) and try to lock all of them in the destructor.
Example (not tested):
vector<shared_ptr<mutex>> mutexesSafe;
~Foo()
{
// ...
for(const auto& m : mutexesSafe)
{
unique_lock l(m);
}
}
void waitOnThing(const string& name)
{
auto m = make_shared<mutex>();
mutexesSafe.push_back(m);
unique_lock lSafe(*m);
//...
}

Related

unique_lock same mutex in different thread

i am looking at this piece of code:
#include <chrono>
#include <iostream>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <string>
#include <thread>
bool flag;
std::mutex m;
void wait_for_flag() {
// std::cout << &m << std::endl;
// return;
std::unique_lock<std::mutex> lk(m);
while (!flag) {
lk.unlock();
std::cout << "unlocked....." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "sleeping....." << std::endl;
lk.lock();
std::cout << "locked by " << std::this_thread::get_id() << "....."
<< std::endl;
}
}
int main(int argc, char const *argv[]) {
std::thread t(wait_for_flag);
std::thread t2(wait_for_flag);
std::thread t3(wait_for_flag);
std::thread t4(wait_for_flag);
std::thread t5(wait_for_flag);
t.join();
t2.join();
t3.join();
t4.join();
t5.join();
return 0;
}
I am new to this, and I thought mutex can only be acquired by one thread. I got two questions:
why there is no deadlock among those threads, e.g. if thread A runs lk.unlock(), then thread B runs lk.lock() and then thread A runs lk.lock().
what does it mean we define a new unique_lock in every thread associating to the same mutex lock (which is called m in here)
Thanks
Because right after acquiring a lock on the mutex each thread calls lk.unlock(); and now other thread can acquire a lock on the mutex. Only if a thread tries to lock an already locked mutex (by a different thread) it has to wait for the mutex to be free. As any thread in your code eventually calls lk.unlock(); there is always a chance for a different thread to get a lock on the mutex and there is no deadlock.
A deadlock would occur for example if you have two mutexes and two threads try to lock them in different order:
// thread A
std::unique_lock<std::mutex> lk1(mutex1);
std::unique_lock<std::mutex> lk2(mutex2); // X
// thread B
std::unique_lock<std::mutex> lk2(mutex2);
std::unique_lock<std::mutex> lk1(mutex1); // X
Here it can happen that thread A locks mutex1, thread B locks mutex2 and then both wait in X for the other thread to release the other mutex, but this will never happen. Its a deadlock.
2.
A lock is merely a slim RAII type. Its only purpose is to call lock on the mutex when created and unlock when destroyed. You can write the same code without the lock, by manually locking / unlocking the mutex, but when there is an exception while a mutex is locked it will never be unlocked.
#SolomonSlow my question is, if we use unique_lock to wrap the mutex in different threads, why there is no deadlock...?
"Deadlock" means that there is some set of threads in which none of the threads can proceed until one of the other members of the set does something. In the simplest possible deadlock, there are just two threads, and there are two mutexes:
Thread A has placed a unique_lock on mutex 1, and it is blocked, waiting to place a lock on mutex 2.
Thread B has placed a lock on mutex 2, and it is blocked, waiting to place a lock on mutex 1.
Thread A can't do anything until thread B does something first, and thread B can't do anything until thread A does something first. Neither thread will ever be able to do anything again. Deadlock.
You can't have a deadlock without at least two different things (e.g., two different mutexes) that the threads wait for. If there's only one mutex, then whichever thread has it locked, that thread will be able to proceed. It's only a deadlock when no thread is able to proceed.
In your example, each of the five threads settles in to a loop:
unlock the mutex,
print, sleep, print,
lock the mutex,
print,
go back to the top of the loop.
Whenever one of your threads locks the mutex, there's nothing to stop it from printing and then going back to the top and unlocking the mutex again so that some other thread can run. There's no deadlock.
This is not an answer. It's just an illustration. I turned your one example into three different examples that all achieve the same result. I hope it may help you to better understand what unique_lock does.
The first way doesn't use unique_lock at all. It only uses the mutex. This is the old-school way—the way we used to do things before RAII was discovered.
std::mutex m;
{
...
while (...) {
do_work_outside_critical_section();
m.lock(); // explicitly put a "lock" on the mutex.
do_work_inside_critical_section();
m.unlock(); // explicitly remove the "lock."
}
}
The old-school way is risky because if do_work_inside_critical_section() throws an exception, it will leave the mutex in a locked state, and any thread that tries to lock it again probably will hang forever.
The second way uses unique_lock, which is an embodiment of RAII.
The RAII pattern ensures that there's no way out of this code block that leaves a lock on mutex m. The unique_lock destructor always will be called, no matter what, and the destructor removes the lock.
std::mutex m;
{
...
while (...) {
do_work_outside_critical_section();
std::unique_lock<std::mutex> lk(m); // constructor puts a "lock" on the mutex.
do_work_inside_critical_section();
} // destructor implicitly removes the "lock."
}
Notice that in this version, a unique_lock is constructed and destructed every time around the loop. That might sound costly, but it really isn't. unique_lock is meant to be used in this way.
The last way is what you did in your example. It only creates and destroys the unique_lock one time, but then it repeatedly locks and unlocks it within the loop. This works, but it's more code lines than the version above, which makes it a little bit harder to read and understand.
std::mutex m;
{
...
std::unique_lock<std::mutex> lk(m); // constructor puts a "lock" on the mutex.
while (...) {
lk.unlock(); // explicitly remove the "lock" from the mutex.
do_work_outside_critical_section();
lk.lock(); // explicitly put a "lock" back on the mutex.
do_work_inside_critical_section();
}
} // destructor implicitly removes the "lock."

Can another tread unlock a mutex although it has not acquired the lock previously?

Can thread t2 unlock a mutex m, although the mutex was previously locked by thread t1? Can the mutex m be unlocked twice?
To illustrate these questions, I wrote the following little script:
#include <atomic>
#include <mutex>
#include <thread>
#include <iostream>
class spinlock_mutex {
std::atomic_flag flag;
public:
spinlock_mutex() : flag(ATOMIC_FLAG_INIT){};
void lock() {
while (flag.test_and_set(std::memory_order_acquire)) {
std::cout << "cloud not acquire lock" << std::endl;
}
std::cout << "acquired lock" << std::endl;
}
void unlock() {
flag.clear(std::memory_order_release);
std::cout << "release lock" << std::endl;
}
};
int main() {
spinlock_mutex mutex{};
std::lock_guard<spinlock_mutex> lock_a(mutex);
std::thread t2([&](){mutex.unlock();});
t2.join();
std::cout << "t2 has unlocked the mutex" << std::endl;
}
Execution of this code prints the following:
acquired lock
release lock
t2 has unlocked the mutex
release lock
It seems to me that the main thread acquired the mutex via the lock_guard facility. Then, thread t2 unlocks the mutex. At the end of the main scope, the destructor of lock_guard unlocks the lock (shouldn't that been unlocked by now?) again. (When I replace the custom spinlock_mutex with std::mutex the program runs without any complaints but of course does not print any information).
So I wonder if thread t2 can indeed unlock a mutex it has not locked, and which mutex does the main thread unlock at the end? cppreference warns of undefined behavior in the description of the unlock function, and I wonder if the program documents this?
The link you shared already has the answer
The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.
"Undefined behavior" in C++ doesn't mean "the program can define it". It literally means "this behavior will never be defined by any conforming compiler". See this question for more details on the terminology.
Specifically, the standard (§32.5.4.2.1) has this to say
The expression m.unlock() is well-formed and has the following semantics:
Preconditions: The calling thread owns the mutex.
And §16.3.2.4 defines a function's preconditions as
Preconditions: the conditions that the function assumes to hold whenever it is called; violation of any preconditions results in undefined behavior.
So unlocking a mutex you don't own in undefined behavior. It could work, it could throw an exception, it could ignore the call, it could summon demons out your nose.
No, this is not allowed.
std::mutex::unlock
The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.

Use of C++ condition variables with atomic predicate but no mutex

I have two threads. One thread acts as a timer thread which at regular intervals of time needs to send a notification to another thread. I intend to use C++ condition variables. (There is a good article on how to use C++ condition variables along with its traps and pitfalls in the following link)
I have the following constraints/conditions :-
The notifying thread need not lock on to a mutex
The notified (or the receiver) thread does some useful section but there is no critical section
The receiver thread is allowed to miss a notification if and only if it is doing useful work
There should be no spurious wakeups.
Using the above link as a guideline I put together the following piece of code
// conditionVariableAtomic.cpp
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <thread>
#include <iostream> // std::cout, std::endl
#include <thread> // std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
std::mutex mutex_;
std::condition_variable condVar;
std::atomic<bool> dataReady{false};
void waitingForWork(){
int i = 0;
while (i++ < 10)
{
std::cout << "Waiting " << std::endl;
{
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck, []{ return dataReady.load(); }); // (1)
dataReady = false;
}
std::cout << "Running " << std::endl;
// Do useful work but no critical section.
}
}
void setDataReady(){
int i = 0;
while (i++ < 10)
{
std::this_thread::sleep_for (std::chrono::seconds(1));
dataReady = true;
std::cout << "Data prepared" << std::endl;
condVar.notify_one();
}
}
int main(){
std::cout << std::endl;
std::thread t1(waitingForWork);
std::thread t2(setDataReady);
t1.join();
t2.join();
std::cout << std::endl;
}
I use an atomic predicate to avoid spurious wakeups, but don't use a lock_guard in the notifying thread.
My question is:
does the above piece of code satisfy the constraints/conditions listed above?
I understand that the receiver thread cannot avoid a mutex, hence the need to use std::unique_lock<std::mutex> lck(mutex_); in the receiver. I have however limited the scope of std::unique_lock<std::mutex> lck(mutex_); i.e. put the following section of code
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck, []{ return dataReady.load(); }); // (1)
dataReady = false;
inside a scope block aka { .... } so that the mutex is unlocked as soon as the wait condition is over (the receiver then does some useful work but since there is no critical section, it does not need to hold on to the mutex for the entire while loop). Could there still be consequences/side effects of this limited scoping in this context ? Or does the unique_lock<std::mutex> need to be locked for the entire while loop?
Your code has a race condition. Between checking the value of dataReady in your wait predicate and actually starting the wait, the other thread can set dataReady and call notify_one. In your example this isn't critical as you'll just miss one notify and wake up a second later on the next one.
Another race condition is that you can set dataReady to true in one thread, set dataReady back to false in the other thread and then call notify_one in the first thread, again this will cause the wait to block for longer than you intended.
You should hold the mutex in both threads when setting dataReady and using the condition variable to avoid these races.
You could avoid the second race condition by using an atomic counter instead of a boolean, incrementing it on one thread then decrementing on the other and in the predicate checking if it is non-zero.

C++ scoped lock in loop blocks another thread

Simple example:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex lock_m;
void childTh() {
while(true) {
//std::this_thread::yield();
//std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::unique_lock<std::mutex> lockChild(lock_m);
std::cout << "childTh CPN1" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
int main(int, char**) {
std::thread thr(childTh);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::unique_lock<std::mutex> lockMain(lock_m);
std::cout << "MainTh CPN1" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(10));
return 0;
}
Main thread blocks on lockMain and never reach "MainTh CPN1". I expect that main thread should acquire lock_m when childTh reach end of iteration because lockChild is destroyed and lock_m is released. But this never happens.
Can you please describe in details why main thread don't have time to acquire the lock before childTh lock it again ?
With sleep_for main can reach "MainTh CPN1", but with yield not.
I know that condition_variable can be used to notify and unblock another thread, but is it possible to use just scoped lock ? So it looks that it is risky to use scoped lock in different threads, even if it the same lock.
In childTh, lockChild doesn't release the mutex until the iteration ends. Right after that iteration ends, it starts the next one. This means you only have the time between the destruction of lockChild and then the initialization of lockChild in the next iteration. Since that happens as basically the next instruction, there basically isn't any time for lockMain to acquire a lock on the mutex. To save CPU cycles a typical lock acquire is going to yield for a short duration, which is not as short as single instruction, so there is basically no chance of lockMain being able to lock the mutex as it would have to be timed perfectly. If you change childTh to
void childTh() {
while(true) {
//std::this_thread::yield();
//std::this_thread::sleep_for(std::chrono::milliseconds(1));
{
std::unique_lock<std::mutex> lockChild(lock_m);
std::cout << "childTh CPN1" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
now you have a 1 second delay between when the mutex is release by lockChild and when it reacquired in the next iteration, which then allows lockMain to acquire the mutex.
Also note that you are not calling join on thr at the end of main. Not doing so causes thr's destructor to throw an exception which will cause your program to terminate imporperly.

unique_lock across threads?

I am having some trouble conceptualizing how unique_lock is supposed to operate across threads. I tried to make a quick example to recreate something that I would normally use a condition_variable for.
#include <mutex>
#include <thread>
using namespace std;
mutex m;
unique_lock<mutex>* mLock;
void funcA()
{
//thread 2
mLock->lock();//blocks until unlock?Access violation reading location 0x0000000000000000.
}
int _tmain(int argc, _TCHAR* argv[])
{
//thread 1
mLock = new unique_lock<mutex>(m);
mLock->release();//Allows .lock() to be taken by a different thread?
auto a = std::thread(funcA);
std::chrono::milliseconds dura(1000);//make sure thread is running
std::this_thread::sleep_for(dura);
mLock->unlock();//Unlocks thread 2's lock?
a.join();
return 0;
}
unique_lock should not be accessed from multiple threads at once. It was not designed to be thread-safe in that manner. Instead, multiple unique_locks (local variables) reference the same global mutex. Only the mutex itself is designed to be accessed by multiple threads at once. And even then, my statement excludes ~mutex().
For example, one knows that mutex::lock() can be accessed by multiple threads because its specification includes the following:
Synchronization: Prior unlock() operations on the same object shall synchronize with (4.7) this operation.
where synchronize with is a term of art defined in 4.7 [intro.multithread] (and its subclauses).
That doesn't look at all right. First, release is "disassociates the mutex without unlocking it", which is highly unlikely that it is what you want to do in that place. It basically means that you no longer have a mutex in your unique_lock<mutex> - which will make it pretty useless - and probably the reason you get "access violation".
Edit: After some "massaging" of your code, and convincing g++ 4.6.3 to do what I wanted (hence the #define _GLIBCXX_USE_NANOSLEEP), here's a working example:
#define _GLIBCXX_USE_NANOSLEEP
#include <chrono>
#include <mutex>
#include <thread>
#include <iostream>
using namespace std;
mutex m;
void funcA()
{
cout << "FuncA Before lock" << endl;
unique_lock<mutex> mLock(m);
//thread 2
cout << "FuncA After lock" << endl;
std::chrono::milliseconds dura(500);//make sure thread is running
std::this_thread::sleep_for(dura); //this_thread::sleep_for(dura);
cout << "FuncA After sleep" << endl;
}
int main(int argc, char* argv[])
{
cout << "Main before lock" << endl;
unique_lock<mutex> mLock(m);
auto a = std::thread(funcA);
std::chrono::milliseconds dura(1000);//make sure thread is running
std::this_thread::sleep_for(dura); //this_thread::sleep_for(dura);
mLock.unlock();//Unlocks thread 2's lock?
cout << "Main After unlock" << endl;
a.join();
cout << "Main after a.join" << endl;
return 0;
}
Not sure why you need to use new to create the lock tho'. Surely unique_lock<mutex> mlock(m); should do the trick (and corresponding changes of mLock-> into mLock. of course).
A lock is just an automatic guard that operates a mutex in a safe and sane fashion.
What you really want is this code:
std::mutex m;
void f()
{
std::lock_guard<std::mutex> lock(m);
// ...
}
This effectively "synchronizes" calls to f, since every thread that enters it blocks until it manages to obtain the mutex.
A unique_lock is just a beefed-up version of the lock_guard: It can be constructed unlocked, moved around (thanks, #MikeVine) and it is itself a "lockable object", like the mutex itself, and so it can be used for example in the variadic std::lock(...) to lock multiple things at once in a deadlock-free way, and it can be managed by an std::condition_variable (thanks, #syam).
But unless you have a good reason to use a unique_lock, prefer to use a lock_guard. And once you need to upgrade to a unique_lock, you'll know why.
As a side-note, the above answers skip over the difference between immediate and deferred locking of mutex:
#include<mutex>
::std::mutex(mu);
auto MyFunction()->void
{
std::unique_lock<mutex> lock(mu); //Created instance and immediately locked the mutex
//Do stuff....
}
auto MyOtherFunction()->void
{
std::unique_lock<mutex> lock(mu,std::defer_lock); //Create but not locked the mutex
lock.lock(); //Lock mutex
//Do stuff....
lock.unlock(); //Unlock mutex
}
MyFunction() shows the widely used immediate lock, whilst MyOtherFunction() shows the deferred lock.