unique_lock across threads? - c++

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.

Related

Can we use two different mutex when waiting on same conditional variable?

Consider below scenario:
Thread 1
mutexLk1_
gcondVar_.wait(mutexLk1);
Thread 2
mutexLk2_
gcondVar_.wait(mutexLk2);
Thread 3
condVar_
gcondVar_.notify_all();
What I observe is that notify_all() does not wake up both the threads but just one on the two. If i were to replace mutexLk2 with mutexLk1. I get a functional code.
To reproduce the issue consider below modified example from cppref
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
std::condition_variable cv;
std::mutex cv_m1;
std::mutex cv_m; // This mutex is used for three purposes:
// 1) to synchronize accesses to i
// 2) to synchronize accesses to std::cerr
// 3) for the condition variable cv
int i = 0;
void waits1()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cerr << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cerr << "...finished waiting. waits1 i == 1\n";
}
void waits()
{
std::unique_lock<std::mutex> lk(cv_m1);
std::cerr << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cerr << "...finished waiting. i == 1\n";
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m);
std::cerr << "Notifying...\n";
}
cv.notify_all();
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(cv_m);
i = 1;
std::cerr << "Notifying again...\n";
}
cv.notify_all();
}
int main()
{
std::thread t1(waits), t2(waits1), t3(waits), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
}
Compilation command
g++ --std=c++17 t.cpp -lpthread
Interesting thing here is that the above code gets stuck on either of the waits (sometimes waits1 runs sometime waits) on a centos 7.9 System with g++ 9.3 version (same behavior with g++ 10 on this system) but with a ubuntu 18.04 system (with g++ 9.4) this works without any issues
Any idea what is the expected behaviour or ideal practice to follow? Because in my used case I need two different mutex to protect different data structures but the trigger is from same conditional variable.
Thanks
It seems you violate standad:
33.5.3 Class condition_variable [thread.condition.condvar]
void wait(unique_lock& lock);
Requires: lock.owns_lock() is true and lock.mutex() is locked by the
calling thread, and either
(9.1) — no other thread is waiting on this condition_variable object
or
(9.2) — lock.mutex() returns the same value for each of the lock
arguments supplied by all concurrently waiting (via wait, wait_for, or
wait_until) threads.
Cleary two threads are waiting and lock.mutex() does not return same.
To elaborate on my comment, there are three things that require synchronization in the question.
There are two independent hunks of data, which the question says are each properly synchronized with two independent mutexes. That's fine, but it's irrelevant.
The third synchronization issue is ensuring that some other specified condition is satisfied in order for some threads to run. That's implemented with a condition variable; so far, so good. But when more than one thread waits for a condition variable, all the waiting threads must use the same mutex. So the code needs a mutex for the threads to use when they wait. While it might be possible to use one or another of the existing mutexes for that synchronization, it seems far more likely that the code needs another mutex, specifically for use when waiting on that condition variable.
When you're dealing with synchronization, resist the urge to share things that manage synchronization; that can get you into trouble.

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

Implementing a Semaphore with std::mutex

As a learning exercise, I'm just trying to make a Semaphore class using std::mutex and a few other things provided by the C++ standard. My semaphore should allow as many readLock() as needed, however a writeLock() can only be acquired after all reads are unlocked.
//Semaphore.h
#include <mutex>
#include <condition_variable>
class Semaphore{
public:
Semaphore();
void readLock(); //increments the internal counter
void readUnlock(); //decrements the internal counter
void writeLock(); //obtains sole ownership. must wait for count==0 first
void writeUnlock(); //releases sole ownership.
int count; //public for debugging
private:
std::mutex latch;
std::unique_lock<std::mutex> lk;
std::condition_variable cv;
};
//Semaphore.cpp
#include "Semaphore.h"
#include <condition_variable>
#include <iostream>
using namespace std;
Semaphore::Semaphore() : lk(latch,std::defer_lock) { count=0; }
void Semaphore::readLock(){
latch.lock();
++count;
latch.unlock();
cv.notify_all(); //not sure if this needs to be here?
}
void Semaphore::readUnlock(){
latch.lock();
--count;
latch.unlock();
cv.notify_all(); //not sure if this needs to be here?
}
void Semaphore::writeLock(){
cv.wait(lk,[this](){ return count==0; }); //why can't std::mutex be used here?
}
void Semaphore::writeUnlock(){
lk.unlock();
cv.notify_all();
}
My test program will writeLock() the semaphore, start a bunch of threads, and then release the semaphore. Immediately afterwards, the main thread will attempt to writeLock() the semaphore again. The idea is that when the semaphore becomes unlocked, the threads will readLock() it and prevent the main thread from doing anything until they all finish. When they all finish and release the semaphore, then the main thread can acquire access again. I realize this may not necessarily happen, but it's one of the cases I'm looking for.
//Main.cpp
#include <iostream>
#include <thread>
#include "Semaphore.h"
using namespace std;
Semaphore s;
void foo(int n){
cout << "Thread Start" << endl;
s.readLock();
this_thread::sleep_for(chrono::seconds(n));
cout << "Thread End" << endl;
s.readUnlock();
}
int main(){
std::srand(458279);
cout << "App Launch" << endl;
thread a(foo,rand()%10),b(foo,rand()%10),c(foo,rand()%10),d(foo,rand()%10);
s.writeLock();
cout << "Main has it" << endl;
a.detach();
b.detach();
c.detach();
d.detach();
this_thread::sleep_for(chrono::seconds(2));
cout << "Main released it" << endl;
s.writeUnlock();
s.writeLock();
cout << "Main has it " << s.count << endl;
this_thread::sleep_for(chrono::seconds(2));
cout << "Main released it" << endl;
s.writeUnlock();
cout << "App End" << endl;
system("pause"); //windows, sorry
return 0;
}
The program throws an exception saying "unlock of unowned mutex". I think the error is in writeLock() or writeUnlock(), but I'm not sure. Can anyone point me in the right direction?
EDIT: There was a std::defer_lock missing when initializing lk in the constructor, however it didn't fix the error I was getting. As mentioned in the comment, this isn't a semaphore and I apologize for the confusion. To reiterate the problem, here is the output that I get (things in parenthesis are just my comments and not actually in the output):
App Launch
Thread Start
Thread Start
Main has it
Thread Start
Thread Start
Thread End (what?)
Main released it
f:\dd\vctools\crt_bld\self_x86\crt\src\thr\mutex.c(131): unlock of unowned mutex
Thread End
Thread End
Thread End
This is definitely not a "semaphore".
Your Semaphore constructor acquires the lock on latch right away, then you unlock it twice because writeUnlock() calls lk.unlock() and the next call to writeLock() tries to wait on a condition variable with an unlocked mutex, which is undefined behaviour, then you the next call to writeUnlock() tries to unlock an unlocked mutex, which is also undefined behaviour.
Are you sure the constructor should lock the mutex right away? I think you want to use std::defer_lock in the constructor, and then lock the mutex in writeLock().

Behavior of condition_variable_any when used with a recursive_mutex?

When using condition_variable_any with a recursive_mutex, will the recursive_mutex be generally acquirable from other threads while condition_variable_any::wait is waiting? I'm interested in both Boost and C++11 implementations.
This is the use case I'm mainly concerned about:
void bar();
boost::recursive_mutex mutex;
boost::condition_variable_any condvar;
void foo()
{
boost::lock_guard<boost::recursive_mutex> lock(mutex);
// Ownership level is now one
bar();
}
void bar()
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
// Ownership level is now two
condvar.wait(lock);
// Does this fully release the recursive mutex,
// so that other threads may acquire it while we're waiting?
// Will the recursive_mutex ownership level
// be restored to two after waiting?
}
By a strict interpretation of the Boost documentation, I concluded that condition_variable_any::wait will not generally result in the recursive_mutex being acquirable by other threads while waiting for notification.
Class condition_variable_any
template<typename lock_type> void wait(lock_type& lock)
Effects:
Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or
this->notify_all(), or spuriously. When the thread is unblocked (for
whatever reason), the lock is reacquired by invoking lock.lock()
before the call to wait returns. The lock is also reacquired by
invoking lock.lock() if the function exits with an exception.
So condvar.wait(lock) will call lock.unlock, which in turn calls mutex.unlock, which decreases the ownership level by one (and not necessarily down to zero).
I've written a test program that confirms my above conclusion (for both Boost and C++11):
#include <iostream>
#define USE_BOOST 1
#if USE_BOOST
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/recursive_mutex.hpp>
namespace lib = boost;
#else
#include <chrono>
#include <thread>
#include <condition_variable>
#include <mutex>
namespace lib = std;
#endif
void bar();
lib::recursive_mutex mutex;
lib::condition_variable_any condvar;
int value = 0;
void foo()
{
std::cout << "foo()\n";
lib::lock_guard<lib::recursive_mutex> lock(mutex);
// Ownership level is now one
bar();
}
void bar()
{
std::cout << "bar()\n";
lib::unique_lock<lib::recursive_mutex> lock(mutex);
// Ownership level is now two
condvar.wait(lock); // Does this fully release the recursive mutex?
std::cout << "value = " << value << "\n";
}
void notifier()
{
std::cout << "notifier()\n";
lib::this_thread::sleep_for(lib::chrono::seconds(3));
std::cout << "after sleep\n";
// --- Program deadlocks here ---
lib::lock_guard<lib::recursive_mutex> lock(mutex);
value = 42;
std::cout << "before notify_one\n";
condvar.notify_one();
}
int main()
{
lib::thread t1(&foo); // This results in deadlock
// lib::thread t1(&bar); // This doesn't result in deadlock
lib::thread t2(&notifier);
t1.join();
t2.join();
}
I hope this helps anyone else facing the same dilemma when mixing condition_variable_any and recursive_mutex.
You can fix this design by adding a parameter allowed_unlock_count to every function which operates on the mutex object; there are two types of guarantees that can be made about allowed_unlock_count:
(permit-unlock-depth) allowed_unlock_count represents the depth of permitted unlocking of mutex: the caller allows bar to unlock the mutex allowed_unlock_count times. After such unlocking, no guarantee is made about the state of mutex.
(promise-unlock) allowed_unlock_count represents the depth of locking of mutex: the caller guarantees that unlocking mutex exactly allowed_unlock_count times will allow other threads to grab the mutex object.
These guarantees are pre- and post-conditions of functions.
Here bar depends on (promise-unlock):
// pre: mutex locking depth is allowed_unlock_count
void bar(int allowed_unlock_count)
{
// mutex locking depth is allowed_unlock_count
boost::unique_lock<boost::recursive_mutex> lock(mutex);
// mutex locking depth is allowed_unlock_count+1
// you might want to turn theses loops
// into an a special lock object!
for (int i=0; i<allowed_unlock_count; ++i)
mutex.unlock();
// mutex locking depth is 1
condvar.wait(lock); // other threads can grab mutex
// mutex locking depth is 1
for (int i=0; i<allowed_unlock_count; ++i)
mutex.lock();
// mutex locking depth is allowed_unlock_count+1
}
// post: mutex locking depth is allowed_unlock_count
Called function must explicitly allowed to decrease locking depth by the caller.