C++ scoped lock in loop blocks another thread - c++

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.

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."

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.

Destroying condition_variable while waiting

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);
//...
}

Is my wait - notify mechanism using std::mutex correct?

I started using std::mutexes to stop a thread and wait for another thread to resume it. It works like this:
Thread 1
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
// Locks it again to pause this thread
myWaitMutex.lock();
Thread 2
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
However I am not sure if this is correct and will work without problems on all platforms. If this is not correct, what is the correct way to implement this in C++11?
The problems with the code
// Ensures the mutex will be locked
while(myWaitMutex.try_lock());
.try_lock() tries to aquire the lock and returns true if successful, i.e., the code says "if we aquire the lock then retry to lock it again and again until we fail". We can never "fail" as we currently own the lock ourselves that we are waiting on, and so this will be an infinite loop. Also, attempting to lock using a std::mutex that the caller have already aquired a lock on is UB, so this is guaranteed to be UB. If not successful, .try_lock() will return false and the while loop will be exited. In other words, this will not ensure that the mutex will be locked.
The correct way to ensure the mutex will be locked is simply:
myWaitMutex.lock();
This will cause the current thread to block (indefinitely) until it can aquire the lock.
Next, the other thread tries to unlock a mutex it does not have a lock on.
// Executed when thread 1 should resume processing:
myWaitMutex.unlock();
This won't work as it's UB to .unlock() on a std::mutex that you don't already have a lock on.
Using locks
When using mutex locks, it's easier to use a RAII ownership-wrapper object such as std::lock_guard. The usage pattern of std::mutex is always: "Lock -> do something in critical section -> unlock". A std::lock_guard will lock the mutex in its constructor, and unlock it in its destructor. No need to worry about when to lock and unlock and such low-level stuff.
std::mutex m;
{
std::lock_guard<std::mutex> lk{m};
/* We have the lock until we exit scope. */
} // Here 'lk' is destroyed and will release lock.
A simple lock might not be the best tool for the job
If what you want is to be able to signal a thread to wake up, then there's the wait and notify structure using std::condition_variable. The std::condition_variable allows any caller to send a signal to waiting threads without holding any locks.
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std::literals;
int main() {
std::mutex m;
std::condition_variable cond;
std::thread t{[&] {
std::cout << "Entering sleep..." << std::endl;
std::unique_lock<std::mutex> lk{m};
cond.wait(lk); // Will block until 'cond' is notified.
std::cout << "Thread is awake!" << std::endl;
}};
std::this_thread::sleep_for(3s);
cond.notify_all(); // Notify all waiting threads.
t.join(); // Remember to join thread before exit.
}
However, to further complicate things there's this thing called spurious wakeups that mean that any waiting threads may wake up at any time for unknown reasons. This is a fact on most systems and has to do with the inner workings of thread scheduling. Also, we probably need to check that waiting is really needed as we're dealing with concurrency. If, for example, the notifying thread happens to notify before we start waiting, then we might wait forever unless we have a way to first check this.
To handle this we need to add a while loop and a predicate that tells when we need to wait and when we're done waiting.
int main() {
std::mutex m;
std::condition_variable cond;
bool done = false; // Flag for indicating when done waiting.
std::thread t{[&] {
std::cout << "Entering sleep..." << std::endl;
std::unique_lock<std::mutex> lk{m};
while (!done) { // Wait inside loop to handle spurious wakeups etc.
cond.wait(lk);
}
std::cout << "Thread is awake!" << std::endl;
}};
std::this_thread::sleep_for(3s);
{ // Aquire lock to avoid data race on 'done'.
std::lock_guard<std::mutex> lk{m};
done = true; // Set 'done' to true before notifying.
}
cond.notify_all();
t.join();
}
There are additional reasons why it's a good idea to wait inside a loop and use a predicate such as "stolen wakeups" as mentioned in the comments by #David Schwartz.
It sounds to me that you are looking for condition variable. In the end there should always be a way to make it work through mutexes, but condition variable is the current C++ idiomatic way to handle the `block and wait until something happens' scenario.
The behavior of a mutex when a thread that holds it attempts to lock it is undefined. The behavior of a mutex when a thread that doesn't hold it attempts to unlock it is undefined. So your code might do anything at all on various platforms.
Instead, use a mutex together with a condition variable and a predicate boolean. In pseudo-code:
To block:
Acquire the mutex.
While the predicate is false, block on the condition variable.
If you want to re-arm here, set the predicate to false.
Release the mutex.
To release:
Acquire the mutex.
Set the predicate to true.
Signal the condition variable.
Release the mutex.
To rearm:
Acquire the mutex.
Set the predicate to false.
Release the mutex.
Please check this code....
std::mutex m_mutex;
std::condition_variable m_cond_var;
void threadOne(){
std::unique_lock<std::mutex> lck(mtx);
while (!ready){
m_cond_var.wait(lck);
}
m_cond_var.notify_all();
}
void threadTwo(){
std::unique_lock<std::mutex> lck(mtx);
read = true;
m_cond_var.notify_all();
}
I hope you will get the solution. And it is very proper!!

Execution not switching between thread (c++11)

I am a beginner in C++11 multithreading. I am working with small codes and came into this problem. Here is the code:
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
std::mutex print_mutex;
void function1()
{
std::cout << "Thread1 started" << std::endl;
while (true)
{
std::unique_lock<std::mutex> lock(print_mutex);
for (size_t i = 0; i<= 1000000000; i++)
continue;
std::cout << "This is function1" << std::endl;
lock.unlock();
}
}
void function2()
{
std::cout << "Thread2 started" << std::endl;
while (true)
{
std::unique_lock<std::mutex> lock(print_mutex);
for (size_t i = 0; i <= 1000000000; i++)
continue;
std::cout << "This is function2" << std::endl;
lock.unlock();
}
}
int main()
{
std::thread t1(function1);
std::thread t2(function2);
t1.join();
t2.join();
return 0;
}
I have written code with the intuition of expecting the following output:
Thread1 started Thread2 started This is
function1 This is function2 This is function1 . . . .
But the output shown is as follows:
Thread1 started Thread2 started
This is function1 This is function1 This is
function1 . . .
Where am I going wrong?
Unlocking a mutex does not guarantee that another thread that's waiting to lock the same mutex will immediately acquire a lock.
It only guarantees that the other thread will TRY to acquire the lock.
In this case, after you unlock the mutex in one thread, the same thread will immediately try to lock it again. Even though another thread was waiting patiently, for the mutex, it's not a guarantee that the other thread will win this time. The same thread that just locked it can succeed in immediately locking it again.
Today, you're seeing that the same thread always wins the locking race. Tomorrow, you may find that it's always the other thread that does. You have no guarantees, whatsoever, which thread will acquire the mutex when there's more than one thread going after the same mutex, at the same time. The winner depends on your CPU and other hardware architecture, how busy the system is loaded, at the time, and many other factors.
Both of your thread is doing following steps:
Lock
Long empty loop
Print
Unlock
Lock
Long empty loop
(and so on)
Practically, you haven't left any time for context switching, there is a lock just right after the unlock. Solution: Swap the "lock" and the "long empty loop" steps, so only the "print" step will be locked, the scheduler can switch to the other thread during "long empty loop".
Welcome to threads!
Edit: Pro Tipp: Debugging multithreading programs is hard. But sometimes it's worth to insert a plain printf() to indicate locks and unlocks (the right order: lock, then printf and printf then unlock), even when the program seems correct. In this case you could see the zero gap between unlock-lock.
This is a valid result, your code does not try to control the execution order in any way so as long as all threads execute at some point and there's is no problem and it's a legitimate result.
This could happen even if you switched the order of the loop and the lock(see here), because again you haven't written anything that attempts to control it using e.g conditional variables or just some silly atomic_bool(it is a silly solution just to demonstrate how can you actually make it alternating and be sure it will) boolean to alternate the runs.