How to atomically check if mutex is locked? - c++

Consider this:
// Somewhere
std::mutex mutex;
std::unique_lock lock{mutex};
std::condition_variable condition;
// Thread01
condition.wait(lock);
// Thread02
while (lock.owns_lock());
So I got a situation like this where the loop at Thread02 never ends, regardless of the fact that Thread01 is waiting for the condition.
This means that unlocking the lock at std::condition_variable::wait does not synchronize with checking if the lock is locked at std::unique_lock::owns_lock. Here it is explicitly told that the wait "Atomically unlocks lock..." but here nothing is told about owns_lock of being atomic or being synchronised with the lock operations.
So the question is: how can I atomically check it the wait has atomically unlocked the lock?
EDIT:
The desire is to know at Thread02 if Thread01 is waiting for the condition. That's why I've accepted the answer.

You can momentarily lock the lock and get the desired Thread02:
// Thread02
std::unique_lock{mutex};
// mutex isn’t locked

Related

How to properly solve the producer consumer in C++11

I'm trying to solve the producer consumer problem in C++11.
I have an object which holds resources, and multiple threads can
add or consume those resources. My problem is when I try to implement
a "consume when available" method on that object.
Please assume that insert/remove operations are of trivial complexity.
A little explanation of the logic in code.
struct ResourceManager{
std::mutex mux;
std::unique_lock lock{mux};
std::condition_variable bell;
void addResource(/*some Resource*/){
lock.lock();
//add resource
lock.unlock();
bell.notify_one(); //notifies waiting consumer threads to consume
}
T getResource(){
while(true){
lock.lock();
if(/*resource is available*/){
//remove resource from the object
lock.unlock();
return resource;
}else{
//new unique lock mutex object wmux creation
lock.unlock(); //problem line
bell.wait(wmux); //waits until addResource rings the bell
continue;
}
}
}
};
Suppose the following scenario:
-Two threads, T1, T2, call addResource, getResource almost simultaneously.
-T2 locks the mutex, and finds out there are no more resources available,
so it has to block until a new resource is available.
So it unlocks the mutex and sets up the bell waiting.
-T1 runs match faster. When the mutex is unlocked,
it immediately adds the resource, and before T2 sets up the waiting bell,
T1 has already rang the bell, which notifies no one.
-T2 indefinitely waits for the bell to ring, but no further resources are added.
I'm making the assumption that a thread locking a mutex, may be the only one
to unlock it. So if I tried calling bell.wait before unlocking the mutex,
the mutex could never be unlocked.
I'd like to use no time-waiting or multiple times checking solution if possible.
So which way could I solve this problem in C++11?
lock.unlock(); //problem line
bell.wait(wmux); //waits until addResource rings the bell
Yes, this is the problem line, indeed.
To correctly use a condition variable as designed, you do not unlock a mutex before wait()ing on its related condition variable. wait()ing on a condition variable atomically unlocks it for the duration of the wait, and reacquires the mutex once the thread has been notify()-ed. Both the unlock-and-wait, and wake-up-after-being-notified-and-lock, are atomic operations.
Allnotify()s should be issued while the mutex is locked. All wait() are also done while the mutex is fully locked. Given that notify(), as I mentioned, is atomic, this results in all mutex-related operations being atomic and fully sequenced, including managing the resources protected by the mutex, and thread notification via condition variables, which is now protected by a mutex as well.
There are design patterns that can be implemented that notify condition variables without using mutex protection. But they're much harder to implement correctly and still achieve thread-safe semantics. Having all condition variable operations also protected by the mutex, in addition to everything else that the mutex protects, is much simpler to implement.
std::condition_variable::wait needs to be passed a locked std::unique_lock on your mutex. wait will unlock the mutex as part of its operation, and will re-lock it before it returns.
The normal way to use lock guards like std::lock_guard and std::unique_lock is to construct them locally and let their constructor lock your mutex and their destructor unlock it.
Also, you can avoid the external while loop in your original code by providing a predicate to std::condition_variable::wait.
struct ResourceManager {
std::mutex mux;
std::condition_variable bell;
void addResource(T resource)
{
std::lock_guard<std::mutex> lock{mux};
// Add the resource
bell.notify_one();
}
T getResource()
{
std::unique_lock<std::mutex> lock{mux};
bell.wait(lock, [this](){ return resourceIsAvailable(); });
return // the ressource
}
};

Condition variable waiting on multiple mutexes

I have a std::condition_variable_any that waits on a custom lock which is a composition of two mutexes (one std::mutex and one shared-locked std::shared_mutex). Its unlock() operation simply unlocks both mutexes sequentially.
For example (pseudocode):
mutex mutex1;
shared_mutex mutex2;
condition_variable_any cv;
// acquiring the locks
DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
// waiting
cv.wait(lock);
cv.wait() should atomically unlock both mutex1 and mutex2, and put the thread to sleep until cv gets notified.
It it still guaranteed that the thread is sleeping and listening to the condition variable notification, once any of mutex1 or mutex2 is unlocked?
Or is it possible that one mutex gets unlocked, and a second thread locks it, sends the notification, but this first thread was not yet sleeping and listening. So the notification never arrived and no wakeup occurs.
If DualLock meets the requirements of BasicLockable, then the code will perform as hoped. If not, it won't.
BasicLockable reference is here
So the notification never arrived and no wakeup occurs.
This can never happen when condition variables are used properly. The wakeup of a condition variable cannot be interpreted as a signal of an event, since the documentation of condition_variable explains that there can be spurious wakeups.
At best, the notification is an indication that now may be a good time to test the condition you're waiting for (and you may do so in the secure knowledge that the test is protected by the mutex).
The state of the condition and the state of the blocked-ness of the current thread are two separate concerns.
Here's a better example (assumes that DualLock models BasicLockable correctly):
bool condition_met = false;
mutex mutex1;
shared_mutex mutex2;
condition_variable_any cv;
// acquiring the locks
DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
while(!condition_met)
{
// waiting
cv.wait(lock);
}
// whatever happens, you have the lock here
// ...work
lock.unlock();
Your notifier would notify this way:
DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
condition_met = true;
lock.unlock(); // note the order: unlock mutex first...
cv.notify_all(); // ...then notify the condition variable

C++ thread: can lock_guard own a mutex that owned by a unique_lock?

In the example code condition variable, it shows that:
After worker thread owns the mutex (unique lock), and then wait.
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
The main thread can still get the mutex (lock guard).
{
std::lock_guard<std::mutex> lk(m);
ready = true;
}
Does this mean that lock_guard can own a mutex that owned by a unique_lock ?
No, it means that during the wait the mutex is unlocked to allow provider threads to lock it and have authority over the cv. You omitted the most significant line in the example code you're referring to, the notify_one:
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one(); // wake up the waiting thread
That's why you need to supply the lock to wait, so it can unlock it before the sleep and attempt to relock it after it has woken up.
From the first section of the page you linked, especially note 2 and 3:
Any thread that intends to wait on std::condition_variable has to
acquire a std::unique_lock, on the same mutex as used to protect the shared variable
execute wait, wait_for, or wait_until. The wait operations atomically release the mutex and suspend the execution of the thread.
When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is atomically reacquired. The thread should then check the condition and resume waiting if the wake up was spurious.

do condition variables unlock their mutex?

I am working with condition variables and I am assuming they unlock their associated mutex on wait. Otherwise, the mutex would never be released. Yet, I can't find this information on any documentation. Consider the following code:
std::condition_variable consumerWakeMeUp;
std::mutex queueMutex;
// this locks the mutex
std::unique_lock<std::mutex> lk(queueMutex);
// going to sleep now
consumerWakeMeUp.wait(lk);
Does the "consumerWakeMeUp.wait(lk)" unlock the mutex? It must I assume otherwise the thread would hand on that mutext forever. But if anyone knows more the details I'd appreciate the input.
thank you.
never mind
"Atomically releases lock, blocks the current executing thread, and adds it to the list of threads waiting on *this. The thread will be unblocked when notify_all() or notify_one() is executed. It may also be unblocked spuriously. When unblocked, regardless of the reason, lock is reacquired and wait exits. If this function exits via exception, lock is also reacquired. (until C++14)"

Spurios wake up and condition variables

I was reading this
nice blog from A Williams:
http://www.justsoftwaresolutions.co.uk/threading/condition-variable-spurious-wakes.html
and one thing bugs me:
when thread wakes up because of the spurious wake does it have mutex locked?
boost::mutex::scoped_lock lock(the_mutex);
while(the_queue.empty())
{
the_condition_variable.wait(lock);
}
I guess so because otherwise call to .empty would be unsafe but Im not sure.
Yes, it does have the mutex locked. Basically, the mutex gets released only while the thread is blocked in the_condition_variable.wait(). Spurious wakeup or not, the mutex is locked everywhere else in the code that you show.
From the documentation for boost::condition_variable::wait():
Postcondition:
lock is locked by the current thread.