I have been trying condition_variable::wait and precisely I am using :
template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
but I am a little bit confused when I executed it. This the simple example:
std::condition_variable cv;
std::mutex cv_m;
bool flag = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cerr << "Waiting... \n";
cv.wait(lk,[]() {return flag == true;});
std::cerr << "...finished waiting " << flag << std::endl;
}
void signals()
{
//std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lk(cv_m);
std::cout <<"Counting...."<< std::endl;
flag = true;
for(int i = 0; i < 5; i++) {
std::cout << i << std::endl;
}
cv.notify_all();
}
int main()
{
std::thread t1(waits), t2(waits), t3(waits), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
if I am delay the signals() with
std::this_thread::sleep_for(std::chrono::seconds(1));
it works as expected while if I put the above line under comment the output it is a mess.
Shouldnd the wait condition put on hold the execution of waits() anyway ? Why do I need a delay the output changes every time and most of the time messed up ?
An example of the output
Waiting...
Counting....
0
1
2
3
4
Waiting...
...finished waiting 1
Waiting...
...finished waiting 1
...finished waiting 1
Thank you for any help
You have a race condition. It is possible for t4 to grab the mutex and run to completion before the other threads have a chance to get into the wait. Thus they miss the signal.
You need to synchronize so that the t1, t2, and t3 get into the wait before t4 starts. Anytime a sleep seems to fix a problem in threaded code, you probably have a race condition that requires real synchronization to fix properly.
Related
I got code like below:
std::mutex mutex;
std::condition_variable condition_variable;
bool finish = false;
void test() {
while (true) {
std::unique_lock<std::mutex> lock(mutex);
condition_variable.wait(lock);
if (finish){
std::cout << "finish detected" << std::endl;
return;
}
}
}
int main() {
std::thread t(test);
std::unique_lock<std::mutex> lock(mutex);
finish = true;
lock.unlock();
//sleep(1);
condition_variable.notify_all();
std::cout << "notify_all" << std::endl;
t.join();
}
and the code will not terminate when running, the notify_all log will print, but the finish detected log will not. If I use debug mode, the code will terminate successfully, so I cannot provide a clear clue about the status of the running code, but if I release the sleep(1), the code will works.
So can anyone help what's wrong with my code?
Condition variables have no state, so that when you signal it and there are no waiters the signal is lost. It happens in your code when condition_variable.notify_all() executes before condition_variable.wait(lock);.
The code doesn't use correct method to wait on the condition variable. The correct method is:
Lock the mutex.
Check the condition (finish here).
If the condition is not satisfied, wait on the condition variable. The condition variable can be woken up spuriously. Goto 2.
Fix:
void test() {
std::unique_lock<std::mutex> lock(mutex);
while(!finish)
condition_variable.wait(lock);
std::cout << "finish detected" << std::endl;
}
There is another overload of condition_variable::wait that does the while loop for you:
void test() {
std::unique_lock<std::mutex> lock(mutex);
condition_variable.wait(lock, [&finish]{ return finish; });
std::cout << "finish detected" << std::endl;
}
attempting:
To do a delayed start on multiple threads.
problem:
I've created the example below to prove out the idea and attempted to create a race codition on x to prove out that all the threads would run concurrently.
It seems like things are serialize instead of running in parallel-the desired behavior, but maybe each thread runs for too short a period and finishes before the other onse get serviced
Sometimes a thread will get stuck on the cv.wait --- I've viewed this in GDB and can see one of the threads just sitting on the wait in frame 0 --- meaning the notify_all did not wak ALL the threads --- (this is sporadic behavior and happens every few attempts at running the binary)
asking:
Is using the condition variable a valid method for performing a delayed startup of a group of threads with the desired behavior that they will all run in parallel?
Why is the notify_all() not waking ALL the threads?
code:
// main.cpp
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
#include <iostream>
#include <unistd.h>
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
std::thread t1 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t1 x:" << x++ << std::endl;});
std::thread t2 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t2 x:" << x++ << std::endl;});
std::thread t3 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t3 x:" << x++ << std::endl;});
std::thread t4 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t4 x:" << x++ << std::endl;});
std::thread t5 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t5 x:" << x++ << std::endl;});
std::cout << "STARTING" << std::endl;
cv.notify_all();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
return 0;
}
compiling:
g++ -std=c++14 main.cpp -lpthread
running:
./a.out
Condition variables are stateless. Notifications get lost if there are no waiters; spurios notifications can be delivered. You need to wait for a change of a shared state, rather than a signal from a condition variable.
std::condition_variable:
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.
Also, when notifying a condition variable the mutex must be held if waiter FIFO order needs to be preserved.
Fixes:
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
bool start = false;
auto thread_fn = [&]{
std::unique_lock<std::mutex> lk(cv_m);
while(!start)
cv.wait(lk);
std::cout << "t1 x:" << x++ << std::endl;
};
std::thread t1 = std::thread(thread_fn);
std::thread t2 = std::thread(thread_fn);
std::thread t3 = std::thread(thread_fn);
std::thread t4 = std::thread(thread_fn);
std::thread t5 = std::thread(thread_fn);
std::cout << "STARTING" << std::endl;
{
std::unique_lock<std::mutex> lock(cv_m);
start = true;
cv.notify_all();
}
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
}
attempting:
To do a delayed start on multiple threads.
problem:
I've created the example below to prove out the idea and attempted to create a race codition on x to prove out that all the threads would run concurrently.
It seems like things are serialize instead of running in parallel-the desired behavior, but maybe each thread runs for too short a period and finishes before the other onse get serviced
Sometimes a thread will get stuck on the cv.wait --- I've viewed this in GDB and can see one of the threads just sitting on the wait in frame 0 --- meaning the notify_all did not wak ALL the threads --- (this is sporadic behavior and happens every few attempts at running the binary)
asking:
Is using the condition variable a valid method for performing a delayed startup of a group of threads with the desired behavior that they will all run in parallel?
Why is the notify_all() not waking ALL the threads?
code:
// main.cpp
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
#include <iostream>
#include <unistd.h>
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
std::thread t1 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t1 x:" << x++ << std::endl;});
std::thread t2 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t2 x:" << x++ << std::endl;});
std::thread t3 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t3 x:" << x++ << std::endl;});
std::thread t4 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t4 x:" << x++ << std::endl;});
std::thread t5 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t5 x:" << x++ << std::endl;});
std::cout << "STARTING" << std::endl;
cv.notify_all();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
return 0;
}
compiling:
g++ -std=c++14 main.cpp -lpthread
running:
./a.out
Condition variables are stateless. Notifications get lost if there are no waiters; spurios notifications can be delivered. You need to wait for a change of a shared state, rather than a signal from a condition variable.
std::condition_variable:
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.
Also, when notifying a condition variable the mutex must be held if waiter FIFO order needs to be preserved.
Fixes:
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
bool start = false;
auto thread_fn = [&]{
std::unique_lock<std::mutex> lk(cv_m);
while(!start)
cv.wait(lk);
std::cout << "t1 x:" << x++ << std::endl;
};
std::thread t1 = std::thread(thread_fn);
std::thread t2 = std::thread(thread_fn);
std::thread t3 = std::thread(thread_fn);
std::thread t4 = std::thread(thread_fn);
std::thread t5 = std::thread(thread_fn);
std::cout << "STARTING" << std::endl;
{
std::unique_lock<std::mutex> lock(cv_m);
start = true;
cv.notify_all();
}
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
}
I am currently trying to learn how to use a condition_variable for thread synchronization. For testing, I have made the demo application shown below. When I start it, it runs into a dead lock. I know the location where this happens, but I'm unable to understand why the deadlock occurs.
I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true, so the main thread should not be blocked in the second pass. But it is just this what happens.
Could anybody explain why?
#include <thread>
#include <condition_variable>
#include <iostream>
bool flag = false;
std::mutex g_mutex;
std::condition_variable cv;
void threadProc()
{
std::unique_lock<std::mutex> lck(g_mutex);
while (true)
{
static int count = 0;
std::cout << "wait for flag" << ++count << std::endl;
cv.wait(lck, []() {return flag; }); // !!!It will blocked at the second round
std::cout << "flag is true " << count << std::endl;
flag = false;
lck.unlock();
}
}
int main(int argc, char *argv[])
{
std::thread t(threadProc);
while (true)
{
static int count = 0;
{
std::lock_guard<std::mutex> guard(g_mutex); // !!!It will blocked at the second round
flag = true;
std::cout << "set flag " << ++count << std::endl;
}
cv.notify_one();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
t.join();
return 0;
}
I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true.
Um..., yes..., Just to be absolutely clear, cv.wait(lck, f) does this:
while(! f()) {
cv.wait(lck);
}
And each call to cv.wait(lck) will;
unlock lck,
wait until some other thread calls cv.notify_one() or cv.notify_all(),
re-lock lck, and then
return.
You can fix the problem by moving the unique_lock(...) statement inside the while loop. As it is now, you're attempting to unlock lck on round 2 but it was not in a locked state, since, after round 1 you never locked it again.
I don't see synchronized output when i comment the the line wait(1) in thread(). can I make them run at the same time (one after another) without having to use 'wait(1)'?
#include <boost/thread.hpp>
#include <iostream>
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
boost::mutex mutex;
void thread()
{
for (int i = 0; i < 100; ++i)
{
wait(1);
mutex.lock();
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
mutex.unlock();
}
}
int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}
"at the same time (one after another)" is contradictory. With a call to sleep() they run at the same time. Without a call to sleep(), they run one after another. With only 100 lines to output, thread t1 completes before t2 has a change to begin execution. On my computer, I had to set your loop counter to 10000 before t1 ran long enough for t2 to launch while t1 was still executing:
Thread 0x2305010: 0
Thread 0x2305010: 1
Thread 0x2305010: 2
...
Thread 0x2305010: 8730
Thread 0x2305010: 8731
Thread 0x23052a0: 0
Thread 0x23052a0: 1
...
Thread 0x23052a0: 146
Thread 0x23052a0: 147
Thread 0x2305010: 8732
Thread 0x2305010: 8733
etc
Oh, and yes, if your goal was to make the two threads take turns executing, boost::condition_variable is the solution:
boost::mutex mutex;
boost::condition_variable cv;
void thread()
{
for (int i = 0; i < 100; ++i)
{
boost::unique_lock<boost::mutex> lock(mutex);
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
cv.notify_one();
cv.wait(lock);
}
cv.notify_one();
}