how to reset std::condition_variable - c++

I am trying to use condition variable to trigger a second thread to do some work after a certain number of buffers are in a deque.
main() is reading ADC data in a tight and time sensitive loop
main() adds the buffer to a deque (that is processed by a thread pool
manager)
the deque depth is variable so a test in main() for depth >= 4 and
then calling notify_one is not possible (ie: during heavy processing
times, the depth of the deque could be as much as 200 or 300 buffers
or as little as 4 during light processing)
thrd() never needs to signal main()
My problem is that in thrd(), after getting the signal and buffers < 4, it cycles back through the while loop and immediately gets the condition again. Is there a way to reset the cv?
deque<int> vbufs;
std::mutex thrdLock;
void thrd()
{
while (true) {
cout << "thrd() waiting for lock\n";
std::unique_lock < std::mutex > lock(thrdLock);
cout << "thrd() waiting for condition\n";
cv.wait(lock, []{ return (vbufs.size() > 0); });
thrdLock.unlock();
cout << "thrd() condition set\n";
if (vbufs.size() >= 4) { // pretend to do something with 4 buffers and remove them
std::lock_guard < std::mutex > lock(thrdLock);
vbufs.pop_front();
vbufs.pop_front();
vbufs.pop_front();
vbufs.pop_front();
cout << "thrd() reducing buffers:" << vbufs.size() << endl;
}
}
}
int main(int argc, char* argv[]) {
std::thread t1(thrd);
int tctr = 0;
while (true) {
usleep(1000);
{
cout << "main() waiting for lock\n";
std::lock_guard < std::mutex > lock(thrdLock);
vbufs.push_back(++tctr);
cout << "main() incremented buffers:" << vbufs.size() << endl;
}
cv.notify_one();
}
return 0;
}

You can't reset a condition variable; it makes no sense - notifying it doesn't change its state so there is nothing to reset. When it is notified only a thread already waiting can be awoken. If that thread then waits again it will not continue until the condition variable is re-notified.
If you only want to do work when there are four or more buffers, shouldn't you change your wait like this?
cv.wait(lock, []{ return (vbufs.size() >= 4); });
What's much more important is that you are potentially reading and writing vbufs simultaneously from two different threads - your if (vbufs.size() >= 4) occurs outside the lock, and so can happen at the same time as the calls to push_back. That leads to undefined behaviour, which may explain what you are seeing.

I found a couple of bugs in the program - corrected here:
Note: the way you were unlocking the mutex directly rather than through the std::unique_lock was causing a data race.
#include <iostream>
#include <deque>
#include <mutex>
#include <thread>
#include <chrono>
#include <condition_variable>
std::deque<int> vbufs;
std::mutex thrdLock;
std::condition_variable cv;
template<class...Ts>
void emit(Ts&&...ts)
{
static std::mutex m;
std::lock_guard<std::mutex> lg(m);
using expand = int[];
void(expand { 0, ((std::cout << std::forward<Ts>(ts)), 0)... });
}
void thrd()
{
while (true) {
emit("thrd() waiting for lock\n");
std::unique_lock < std::mutex > lock(thrdLock);
emit("thrd() waiting for condition\n");
cv.wait(lock, []{ return vbufs.size() >= 4; });
emit("thrd() condition set\n");
auto a = vbufs.front(); vbufs.pop_front();
auto b = vbufs.front(); vbufs.pop_front();
auto c = vbufs.front(); vbufs.pop_front();
auto d = vbufs.front(); vbufs.pop_front();
emit("thrd() reducing buffers:", vbufs.size(), '\n');
lock.unlock();
emit(a, ' ', b, ' ', c, ' ', d, '\n');
}
}
int main(int argc, char* argv[]) {
std::thread t1(thrd);
int tctr = 0;
while (true) {
std::this_thread::sleep_for(std::chrono::microseconds(10));
{
emit("main() waiting for lock\n");
std::lock_guard < std::mutex > lock(thrdLock);
vbufs.push_back(++tctr);
emit("main() incremented buffers:", vbufs.size(), '\n');
}
cv.notify_one();
}
t1.join(); // un-necessary in this case, but...
return 0;
}

Related

C++Mutex and conditional Variable Unlocking/Synchronisation

I'm wanting to have several threads all waiting on a conditional variable (CV) and when the main thread updates a variable they all execute. However, I need the main thread to wait until all these have completed before moving on. The other threads don't end and simply go back around and wait again, so I can't use thread.join() for example.
I've got the first half working, I can trigger the threads, but the main just hangs and doesn't continue. Below is my current code
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <Windows.h>
#define N 3
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
bool finished[N];
void print_id(int id) {
while (1) {
std::unique_lock<std::mutex> lck(mtx); //Try and Lock the Mutex
while (finished[id]) cv.wait(lck); //Wait until finished is false
// ...
std::cout << "thread " << id << '\n';
finished[id] = true; //Set finished to be true. When true, program should continue
}
}
int main()
{
std::thread threads[N];
// spawn 10 threads:
for (int i = 0; i < N; ++i) {
threads[i] = std::thread(print_id, i); //Create n threads
finished[i] = true; //Set default finished to be true
}
std::cout << "N threads ready to race...\n";
for (int i = 0; i < 5; i++) {
std::unique_lock<std::mutex> lck(mtx); //Lock mutex
for (int i = 0; i < N; i++) {
finished[i] = false; //Set finished to false, this will break the CV in each thread
}
cv.notify_all(); //Notify all threads
cv.wait(lck, [] {return finished[0] == true; }); //Wait until all threads have finished (but not ended)
std::cout << "finished, Sleeping for 2s\n";
Sleep(2000);
}
return 0;
}
Thank you.
Edit: I am aware I am only currently checking the status of the finished[0] and not each one. This is done just for simplicity atm and would eventually need to be all of them. I will write a function to manage this later.
You have cv.wait(lck, [] {return finished[0] == true; }); in main thread, but it is not being notified.
You'd need to notify it, and you'd better use another condition_variable for it, not the same as for worker thead notifiecation.

Race condition 2 threads alternating

so i want the program to ouput 1\n2\n1\n2\n1\n2\n but it seems to get stuck somewhere. But when i debug it and set a breackpoint at cv1.notify_one() right after declaring t2 it executes ??
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
cv1.wait(lck1);
cout << "1" << endl;
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
cv2.wait(lck2);
cout << "2" << endl;
cv1.notify_one();
}
});
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
There are several flaws:
You want to guard your output. Therefor you need just one mutex so only one thread can do their work at a time.
You are potentially missing out notifications to your condition variables.
Your global unique_locks aquire the locks of the mutexs in their constructors. So you are holding the locks the whole time and no thread can make progress. Your global unique_locks aquire the locks of the mutexs in their constructors. This is done in the main thread. T1 and T2 are unlocking them through the condition_variable. This is undefined behaviour (thread that owns mutex must unlock it).
This is a recipe to use the condition variable approach correctly:
Have a condition you are interested in. In this case some kind of variable to remember who's turn it is.
Guard this variable by a (ONE!) mutex
Use a (ONE!) condition_variable in conjunction with the mutex of point 2 and the condition of point 1.
This ensures:
There is at any time only one thread which can look and/or change the condition you have.
If a thread is reaching the point in code where it possibly waits for the condition variable, it first checks the condition. Maybe the thread does not even need to go to sleep since the condition he wanna wait for is already true. To do so, the thread has to aquire the mutex, check the condition and decides what to do. While doing so, he owns the lock. The condition cant change because the thread has the lock itself. So you cant miss out a notification.
This leads to the following code ( see live here ):
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
int main(int argc, char** argv)
{
condition_variable cv;
mutex mtx;
bool runt1 = true;
bool runt2 = false;
constexpr int COUNT = 3;
thread t1([&]()
{
for(int i = 0; i < COUNT; ++i)
{
unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&](){ return runt1; });
cout << "1" << endl;
runt1 = false;
runt2 = true;
lck.unlock();
cv.notify_one();
}
});
thread t2([&]()
{
for(int i = 0; i < COUNT; ++i)
{
unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&](){ return runt2; });
cout << "2" << endl;
runt1 = true;
runt2 = false;
lck.unlock();
cv.notify_one();
}
});
t1.join();
t2.join();
return 0;
}
I think you have a data race between your threads starting and the call to cv1.notify_one(); in main().
Consider the case when cv1.notify_one() call happens before thread 1 has started and called cv1.wait(). After that no one calls cv1.notify anymore and your cv-s are just waiting. This is called Lost Wake-up.
You need a mechanism to wait in main till both threads have started, then execute cv1.notify()
Below is an example using int and a mutex.
#include "pch.h"
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
condition_variable cv1, cv2;
mutex m;
const int COUNT = 3;
enum Turn
{
T1,
T2
};
int main(int argc, char** argv)
{
mutex thread_start_mutex;
int num_started_threads = 0;
Turn turn = T1;
thread t1([&]() {
{
// increase the number of started threads
unique_lock<std::mutex> lck(thread_start_mutex);
++num_started_threads;
}
for (int i = 0; i < COUNT; ++i)
{
// locked cout, unlock before calling notify
{
unique_lock<std::mutex> lck1(m);
// wait till main thread calls notify
cv1.wait(lck1, [&] { return turn == T1;});
cout << "1 a really long string" << endl;
turn = T2; // next it's T2's turn
}
cv2.notify_one();
}
});
thread t2([&]() {
{
// increase the number of started threads
unique_lock<std::mutex> lck(thread_start_mutex);
++num_started_threads;
}
for (int i = 0; i < COUNT; ++i)
{
// locked cout, unlock before calling notify
{
unique_lock<std::mutex> lck2(m);
cv2.wait(lck2, [&] {return turn == T2;});
cout << "2 some other stuff to test" << endl;
turn = T1;
}
cv1.notify_one();
}
});
unique_lock<std::mutex> lck(thread_start_mutex);
// wait until both threads have started
cv1.wait(lck, [&] { return num_started_threads == 2; });
lck.unlock();
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
Also it's unclear why you have two mutexes that are locked outside of main. I usually think of a mutex as something that is protected a resource that should not be accessed concurrently. Seems like the idea was to protect the cout calls, for which you should use one mutex, that each thread will lock, do the cout, unlock and notify the other one.
Edit
My original answer had exact same issue between calls to t1.notify() and t2.wait().
If t1.notify() was called before thread 2 was waiting, thread 2 never got woken up.
To address this I added an enum "Turn" which indicates who's turn it is, and each wait condition now checks if it's their turn or not.
If it is, they are not waiting and just printing out, so even if notify was missed they'd still do their task. If it is not their turn, they'll block until the other thread sets turn variable and calls notify.
NOTE: This demonstrates a good example/practice that it's usually much better to have a condition when using cv.wait(). This both makes intentions clear, and avoids both Lost Wake-up and Spurious Wake-ups.
NOTE 2 this solution might be overly complicated, and in general condition variables and mutexes are unlikely the best approach for this problem.
The other answer is right conceptually but still has another race condition. I ran the code and it would still deadlock.
The issue is that t1 is created, but it does not get to cv1.wait(lck1) until after the cv1.notify_one() executes. Thus your two threads sit together forever waiting. You demonstrate this when you put your breakpoint on that line, allowing the thread to catch up. Also, this issue persists when one thread finishes but doesn't give the other time to call wait() so it just calls notify_one. This can be seen, also fixed* (used loosely), by adding some usleep(100) calls from unistd.h.
See below:
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <unistd.h>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
cv1.wait(lck1);
cout << "1\n";
usleep(100);
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
cv2.wait(lck2);
cout << "2\n";
usleep(100);
cv1.notify_one();
}
});
usleep(1000);
cv1.notify_one();
t1.join();
t2.join();
return 0;
}
EDIT: To do better would be to check for waiting threads, which is not built into the mutexes you use. The proper way might be to create your own mutex wrapper class and include that functionality in the class, but for simplicity sake, I just made a waiting variable.
See below:
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <unistd.h>
using namespace std;
mutex cout_lock;
condition_variable cv1, cv2, cv3;
mutex mtx1;
unique_lock<std::mutex> lck1(mtx1);
mutex mtx2;
unique_lock<std::mutex> lck2(mtx2);
int waiting = 0;
const int COUNT = 3;
int main(int argc, char** argv)
{
thread t1([&](){
for(int i = 0; i < COUNT; ++i)
{
waiting++;
cv1.wait(lck1);
cout << "1\n";
waiting--;
if(!waiting)
usleep(100);
cv2.notify_one();
}
});
thread t2([&](){
for(int i = 0; i < COUNT; ++i)
{
waiting++;
cv2.wait(lck2);
cout << "2\n";
waiting--;
if(!waiting)
usleep(100);
cv1.notify_one();
}
});
if(!waiting)
usleep(100);
cv1.notify_one();
t1.join();
t2.join();
return 0;
}

Why is std::mutex taking a long, highly irregular amount of time to be shared?

This code demonstrates that the mutex is being shared between two threads, but one thread has it nearly all of the time.
#include <thread>
#include <mutex>
#include <iostream>
#include <unistd.h>
int main ()
{
std::mutex m;
std::thread t ([&] ()
{
while (true)
{
{
std::lock_guard <std::mutex> thread_lock (m);
sleep (1); // or whatever
}
std::cerr << "#";
std::cerr.flush ();
}
});
while (true)
{
std::lock_guard <std::mutex> main_lock (m);
std::cerr << ".";
std::cerr.flush ();
}
}
Compiled with g++ 7.3.0 on Ubuntu 18.04 4.15.0-23-generic.
The output is a mix of both # and . characters, showing that the mutex is being shared, but the pattern is surprising. Typically something like this:
.......#####..........................##################......................##
i.e. the thread_lock locks the mutex for a very long time. After several or even tens of seconds, the main_lock receives control (briefly) then the thread_lock gets it back and keeps it for ages. Calling std::this_thread::yield() doesn't change anything.
Why are the two mutexes not equally likely to gain the lock, and how can I make the mutex be shared in a balanced fashion?
std::mutex isn't designed to be fair. It doesn't guarantee that the order of locking is kept, you're either lucky to get the lock or not.
If you want more fairness, consider using a std::condition_variable like so :
#include <thread>
#include <mutex>
#include <iostream>
#include <condition_variable>
#include <unistd.h>
int main ()
{
std::mutex m;
std::condition_variable cv;
std::thread t ([&] ()
{
while (true)
{
std::unique_lock<std::mutex> lk(m);
std::cerr << "#";
std::cerr.flush ();
cv.notify_one();
cv.wait(lk);
}
});
while (true)
{
std::unique_lock<std::mutex> lk(m);
std::cerr << ".";
std::cerr.flush ();
cv.notify_one();
cv.wait(lk);
}
}
Making std::mutex fair would have a cost. And in C++ you don't pay for what you don't ask for.
You could write a locking object where the party releasing the lock cannot be the next one to get it. More advanced, you could write one where this only occurs if someone else is waiting.
Here is a quick, untested stab at a fair mutex:
struct fair_mutex {
void lock() {
auto l = internal_lock();
lock(l);
}
void unlock() {
auto l = internal_lock();
in_use = false;
if (waiting != 0) {
loser=std::this_thread::get_id();
} else {
loser = {};
}
cv.notify_one();
}
bool try_lock() {
auto l = internal_lock();
if (in_use) return false;
lock(l);
return true;
}
private:
void lock(std::unique_lock<std::mutex>&l) {
++waiting;
cv.wait( l, [&]{ return !in_use && std::this_thread::get_id() != loser; } );
in_use = true;
--waiting;
}
std::unique_lock<std::mutex> internal_lock() const {
return std::unique_lock<std::mutex>(m);
}
mutable std::mutex m;
std::condition_variable cv;
std::thread::id loser;
bool in_use = false;
std::size_t waiting = 0;
};
it is "fair" in that if you have two threads contending over a resource, they will take turns. If someone is waiting on a lock, anyone giving up the lock won't grab it again.
This is, however, threading code. So I might read it over, but I wouldn't trust my first attempt to write anything.
You could extend this (at increasing cost) to be n-way fair (or even omega-fair) where if there are up to N elements waiting, they all get their turn before the releasing thread gets another chance.

C++11: condition variable only works for once

I have this piece of code:
std::unique_lock<std::mutex> lock(m_mutex);
for(;;)
{
// wait for input notification
m_event.wait(lock);
// if there is an input pin doesn't have any data, just wait
for(DataPinIn* ptr:m_in_ports)
if(ptr->m_data_dup==NULL)
continue;
// do work
Work(&m_in_ports,&m_out_ports);
// this might need a lock, we'll see
for(DataPinIn* ptr:m_in_ports)
{
// reduce the data refcnt before we lose it
ptr->FreeData();
ptr->m_data_dup=NULL;
std::cout<<"ptr:"<<ptr<<"set to 0\n";
}
}
in which m_event is a condition_variable.
It waits for notification from another thread and then does some works. But I found out that this only succeeds for the first time and it blocks on m_event.wait(lock) forever, no matter how many times m_event.notify_one() is called. How should I solve this?
Thanks in advance.
You are experiencing the common scenario 'spurious wakeup' (please consult wiki) which condition_variable is desgined to solve.
Please read the sample code in this article: http://www.cplusplus.com/reference/condition_variable/condition_variable/.
Usually condition_variable must be used together with a certain variable to avoid spurious wakeups; that's how the synchronization method is named.
Below is a better piece of sample code:
#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>
#include <queue>
#include <chrono>
int main()
{
std::queue<int> produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool done = false;
bool notified = false;
std::thread producer([&]() {
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lock(m);
std::cout << "producing " << i << '\n';
produced_nums.push(i);
notified = true;
cond_var.notify_one();
}
done = true;
cond_var.notify_one();
});
std::thread consumer([&]() {
std::unique_lock<std::mutex> lock(m);
while (!done) {
while (!notified) { // loop to avoid spurious wakeups
cond_var.wait(lock);
}
while (!produced_nums.empty()) {
std::cout << "consuming " << produced_nums.front() << '\n';
produced_nums.pop();
}
notified = false;
}
});
producer.join();
consumer.join();
}
It turns out that a flag variable ruined everything and the threading part is working correctly.

Some boost thread questions C++

I am using boost::thread, and I meet some problems.
The thing is, are there any ways I can join a thread before the last join finish?
for example,
int id=1;
void temp()
{
int theardID = id++;
for(int i=0;i<3;i++)
{
cout<<theardID << " : "<<i<<endl;
boost::this_thread::sleep(boost::posix_time::millisec(100));
}
}
int main(void)
{
boost::thread thrd1(temp);
thrd1.join();
boost::thread thrd2(temp);
boost::thread thrd3(temp);
thrd2.join();
thrd3.join();
return 0;
}
In this simple example, the order of output may be:
1:0
1:1
1:2
2:0
3:0
3:1
2:1
2:2
3:2
As the above example, we can see find out that thrd2 and thrd3 start to run after thrd1 finish.
Are there any ways to let thrd2 and thrd3 run before thrd1 finish?
You can use Boost.Thread's condition variables to synchronize on a condition more complex than what join can provide. Here's a example based on yours:
#include <iostream>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
boost::mutex mutex;
boost::condition_variable cond;
// These three variables protected by mutex
bool finishedFlag = false;
int finishedID = 0;
int finishedCount = 0;
int id=1;
void temp()
{
int threadID = id++;
for(int i=0;i<3;i++)
{
std::cout << threadID << " : " << i << std::endl;
boost::this_thread::sleep(boost::posix_time::millisec(100));
}
{
boost::lock_guard<boost::mutex> lock(mutex);
finishedFlag = true;
finishedID = threadID;
++finishedCount;
}
cond.notify_one();
}
int main(void)
{
boost::thread thrd1(temp);
boost::this_thread::sleep(boost::posix_time::millisec(300));
boost::thread thrd2(temp);
boost::thread thrd3(temp);
boost::unique_lock<boost::mutex> lock(mutex);
while (finishedCount < 3)
{
while (finishedFlag != true)
{
// mutex is released while we wait for cond to be signalled.
cond.wait(lock);
// mutex is reacquired as soon as we finish waiting.
}
finishedFlag = false;
if (finishedID == 1)
{
// Do something special about thrd1 finishing
std::cout << "thrd1 finished" << std::endl;
}
};
// All 3 threads finished at this point.
return 0;
}
The join function means "stop this thread until that thread finishes." It's a simple tool for a simple purpose: ensuring that, past this point in the code, thread X is finished.
What you want to do isn't a join operation at all. What you want is some kind of synchronization primitive to communicate and synchronize behavior between threads. Boost.Thread has a number of alternatives for synchronization, from conditions to mutexes.