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
}
};
Related
While implementing a thread pool pattern in C++ based on this, I came across a few questions.
Let's assume minimal code sample:
std::mutex thread_mutex;
std::condition_variable thread_condition;
void thread_func() {
std::unique_lock<std::mutex> lock(thread_mutex);
thread_condition.wait(lock);
lock.unlock();
}
std::thread t1 = std::thread(thread_func);
Regarding cppreference.com about conditon_variable::wait(), wait() causes the current thread to block. What is locking the mutex then for when I only need one thread at all using wait() to get notified when something is to do?
unique_lock will block the thread when the mutex already has been locked by another thread. But this wouldn't be neccesary as long as wait() blocks anyway or what do I miss here?
Adding a few lines at the bottom...
std::thread t2 = std::thread(thread_func);
thread_condition.notify_all()
When unique_lock is blocking the thread, how will notify_all() reach both threads when one of them is locked by unique_lock and the other is blocked by wait()? I understand that blocking wait() will be freed by notify_all() which afterwards leads to unlocking the mutex and that this gives chance to the other thread for locking first the mutex and blocking thread by wait() afterwards. But how is this thread notified than?
Expanding this question by adding a loop in thread_func()...
std::mutex thread_mutex;
std::condition_variable thread_condition;
void thread_func() {
while(true) {
std::unique_lock<std::mutex> lock(thread_mutex);
thread_condition.wait(lock);
lock.unlock();
}
}
std::thread t1 = std::thread(thread_func);
std::thread t2 = std::thread(thread_func);
thread_condition.notify_all()
While reading documentation, I would now expect both threads running endlessly. But they do not return from wait() lock. Why do I have to use a predicate for expected behaviour like this:
bool wakeup = false;
//[...]
thread_condition.wait(lock, [] { return wakeup; });
//[...]
wakeup = !wakeup;
thread_condition.notify_all();
Thanks in advance.
This is really close to being a duplicate, but it's actually that question that answers this one; we also have an answer that more or less answers this question, but the question is distinct. I think that an independent answer is needed, even though it's little more than a (long) definition.
What is a condition variable?
The operational definition is that it's a means for a thread to block until a message arrives from another thread. A mutex alone can't possibly do this: if all other threads are busy with unrelated work, a mutex can't block a thread at all. A semaphore can block a lone thread, but it's tightly bound to the notion of a count, which isn't always appropriate to the nature of the message to receive.
This "channel" can be implemented in several ways. Very low-tech is to use a pipe, but that involves expensive system calls. Windows provides the Event object which is fundamentally a boolean on whose truth a thread may wait. (C++20 provides a similar feature with atomic_flag::wait.)
Condition variables take a different approach: their structural definition is that they are stateless, but have a special connection to a corresponding mutex type. The latter is necessitated by the former: without state, it is impossible to store a message, so arrangements must be made to prevent sending a message during some interval between a thread recognizing the need to wait (by examining some other state: perhaps that the queue from which it wants to pop is empty) and it actually being blocked. Of course, after the thread is blocked it cannot take any action to allow the message to be sent, so the condition variable must do so.
This is implemented by having the thread take a mutex before checking the condition and having wait release that mutex only after the thread can receive the message. (In some implementations, the mutex is also used to protect the workings of the condition variable, but C++ does not do so.) When the message is received, the mutex is re-acquired (which may block the thread again for a time), as is necessary to consult the external state again. wait thus acts like an everted std::unique_lock: the mutex is unlocked during wait and locked again afterwards, with possibly arbitary changes having been made by other threads in the meantime.
Answers
Given this understanding, the individual answers here are trivial:
Locking the mutex allows the waiting thread to safely decide to wait, given that there must be some other thread affecting the state in question.
If the std::unique_lock blocks, some other thread is currently updating the state, which might actually obviate the need for wait.
Any number of threads can be in wait, since each unlocks the mutex when it calls it.
Waiting on a condition variable, er, unconditionally is always wrong: the state you're after might already apply, with no further messages coming.
The documentation of the notify_one() function of condition variable at cppreference.com states the following
The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s); in fact doing so is a pessimization, since the notified thread would immediately block again, waiting for the notifying thread to release the lock.
The first part of the sentence is strange, if I hold different mutexes in the notifying and notified threads, then the mutexes have no real meaning as the there is no 'blocking' operation here. In fact, if different mutexes are held, then the likelihood that a spurious wake up could cause the notification to be missed is possible! I get the impression that we might as well not lock on the notifying thread in such a case. Can someone clarify this?
Consider the following from cppreference page on condition variables as an example.
std::mutex m; // this is supposed to be a pessimization
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Wait until main() sends data
std::unique_lock<std::mutex> lk(m); // a different, local std::mutex is supposedly better
cv.wait(lk, []{return ready;});
// after the wait, we own the lock.
std::cout << "Worker thread is processing data\n";
data += " after processing";
// Send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completed\n";
lk.unlock();
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m); // a different, local std::mutex is supposedly better
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return processed;});
}
std::cout << "Back in main(), data = " << data << '\n';
worker.join();
}
PS. I saw a few questions that are similarly titled but they refer to different aspects of the problem.
I think the wording of cppreference is somewhat awkward here. I think they were just trying to differentiate the mutex used in conjunction with the condition variable from other unrelated mutexes.
It makes no sense to use a condition variable with different mutexes. The mutex is used to make any change to the actual semantic condition (in the example it is just the variable ready) atomic and it must therefore be held whenever the condition is updated or checked. Also it is needed to ensure that a waiting thread that is unblocked can immediately check the condition without again running into race conditions.
I understand it as follows:
It is OK, not to hold the lock on the mutex associated with the condition variable when notify_one is called, or any mutex at all, however it is OK to hold other mutexes for different reasons.
The pessimisation is not that only one mutex is used, but to hold this mutex for longer than necessary when you know that another thread is supposed to immediately try to acquire the mutex after being notified.
I think that my interpretation agrees with the explanation given in cppreference on condition variable:
The thread that intends to modify the shared variable has to
acquire a std::mutex (typically via std::lock_guard)
perform the modification while the lock is held
execute notify_one or notify_all on the std::condition_variable (the lock does not need to be held for notification)
Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread.
Any thread that intends to wait on std::condition_variable has to
acquire a std::unique_lock<std::mutex>, on the same mutex as used to protect the shared variable
Furthermore the standard expressly forbids using different mutexes for wait, wait_for, or wait_until:
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.
The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s);
That's misleading. The problem is the word, "same." They should have said, "...does not need to hold the lock on any mutex..." That's the real point. There's an important reason why the waiting thread should have a mutex locked when it enters the wait() call: It's awaiting some change in some shared data structure, and it needs the mutex to be locked when it accesses the structure to check whether or not the awaited change actually has happened.
The notify()ing thread probably needs to lock the same mutex in order to effect that change, but the correctness of the program won't depend on whether it calls notify() before or after it releases the mutex.
When using a condition variable, http://en.cppreference.com/w/cpp/thread/condition_variable describes the typical steps for the thread that notifies as:
acquire a std::mutex (typically via std::lock_guard)
perform the modification while the lock is held
execute notify_one or notify_all on the std::condition_variable (the lock does not need to be held for notification)
For the simple case shown below, is it necessary for the main thread to lock "stop" when it modifies it? While I understand that locking when modifying shared data is almost always a good idea, I'm not sure why it would be necessary in this case.
std::condition_variable cv;
std::mutex mutex;
bool stop = false;
void worker() {
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [] { return stop; })
}
// No lock (Why would this not work?)
void main() {
std::thread(worker);
std::this_thread::sleep_for(1s);
stop = true;
cv.notify_one();
}
// With lock: why is this neccesary?
void main() {
std::thread mythread(worker);
std::this_thread::sleep_for(1s);
{
std::unique_lock<std::mutex>(mutex);
stop = true;
}
cv.notify_one();
mythread.join();
}
For the simple case shown below, is it necessary for the main thread to lock "stop" when it modifies it?
Yes, to prevent race condition. Aside from issues of accessing shared data from different threads, which could be fixed by std::atomic, imagine this order of events:
worker_thread: checks value of `stop` it is false
main_thread: sets `stop` to true and sends signal
worker_thread: sleeps on condition variable
In this situation worker thread would possibly sleep forever and it would miss event of stop set to true simply because wakeup signal was already sent and it missed it.
Acquiring mutex on modification of shared data is required because only then you can treat checking condition and going to sleep or acting on it in worker thread as atomic operation as whole.
Is , it is necessary.
First of all, from the standard point of view, you code exhibits undefined behavior, as stop is not atomic and isn't change under a lock, while other threads may read or write to it. both reading and writing must occur under a lock if multiple threads read and write to a shared memory.
From hardware perspective, if stop isn't changed under a lock, other threads, even through they lock some lock, aren't guaranteed to "see" the change that was done. locks don't just prevent from other threads to intervene, they also force the latest change to be read or written into the main memory, and hence all the threads can work with the latest values.
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
I have a class that opens transactions, adds operations to a queue, then closes the transaction. Across the open->close lifetime I would like to employ a recursive mutex, so that only one thread can have a transaction open at any time. All other threads are blocked until the current transaction is ended.
class MyObject
{
void beginTransaction()
{
// acquire mutex
}
void endTransaction()
{
// release mutex
}
boost::recursive_mutex m_mutex;
}
I am having difficulty determining how I can use a recursive_mutex in this case, as the lock would exist longer than the scope of a single method. Can anyone suggest how I might apply locking here?
Boost (and the standard library) provide mutexes, which can be locked and unlocked, and locks, which lock mutexes in their constructor and unlocks them in their destructor. Locks are really just lightweight wrappers that are used to ensure a lock is released when leaving scope.
In your case, you would just use the mutex directly, without wrapping it in a lock.
You can call m_mutex.lock() in beginTransaction to lock the mutex, then m_mutex.unlock() in endTransaction to unlock the mutex. If another thread attempts to call m_mutex.lock() between calls, it will block until the mutex is unlocked by the owning thread in endTransaction