I have implemented a sample program to understand how wait_for and wait_until works in C++11.
Code -
#include <iostream>
#include <future>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
using namespace std::chrono;
condition_variable cv;
mutex m;
bool flagValue=false;
int sampleFunction(int a)
{
cout<<"Executing sampleFunction...";
cout.flush();
this_thread::sleep_for(seconds(5));
cout<<"Done."<<endl;
return a;
}
void sampleFunctionCond(int a)
{
lock_guard<mutex> lg(m);
cout<<"Executing sampleFunctionCond...";
cout.flush();
this_thread::sleep_for(seconds(5));
cout<<"Done."<<endl;
cout<<"Value : "<<a<<endl;
flagValue=true;
cv.notify_one();
return;
}
int main()
{
unique_lock<mutex> ul(m);
future<int> f1=async(launch::async,sampleFunction,10);
future_status statusF1=f1.wait_for(seconds(1));
if(statusF1==future_status::ready)
cout<<"Future is ready"<<endl;
else if (statusF1==future_status::timeout)
cout<<"Timeout occurred"<<endl;
else if (statusF1==future_status::deferred)
cout<<"Task is deferred"<<endl;
cout<<"Value : "<<f1.get()<<endl;
cv_status statusF2;
thread t1(sampleFunctionCond,20);
t1.detach();
while(!flagValue)
{
statusF2=cv.wait_until(ul,system_clock::now()+seconds(2));
if(statusF2==cv_status::timeout)
{
cout<<"Timeout occurred."<<endl;
break;
}
else
{
cout<<"Condition variable is ready or spurious wake up occurred."<<endl;
}
}
}
Output -
Executing sampleFunction...Timeout occurred
Done.
Value : 10
Executing sampleFunctionCond...Done.
Value : 20
Timeout occurred.
sampleFunction is working as expected as its printing "Timeout occurred" before "Done" but same is not the case with sampleFunctionCond. Though it knows wait_until has timed out but its printing the message after the function sampleFunctionCOnd has finished executing.
Can someone please help me understand this? Thanks.
There is a race condition in statusF2=cv.wait_until(...); statement. What may happen is that the wait has timed out and is about to return. To return it needs to reacquire the mutex. At the same time the other thread has acquired the mutex. So, statusF2=cv.wait_until(...); can't return till the other thread has set flagValue to true and released the mutex.
To fix the code the value of flagValue must be checked before checking whether the wait timed out.
The function "sampleFunctionCond" should not hold the mutex "m" all time. You can try to lock "m" immediately before the line "flagValue=true;".
Related
This question already has answers here:
Why do you need a while loop while waiting for a condition variable
(4 answers)
Closed 1 year ago.
Why is it necessary to use while() with std::condition_variable::wait()
in this code:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id (int id) {
std::unique_lock<std::mutex> lck(mtx);
while (!ready) cv.wait(lck);
// ...
std::cout << "thread " << id << '\n';
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_id,i);
std::cout << "10 threads ready to race...\n";
go(); // go!
for (auto& th : threads) th.join();
return 0;
}
If, as I understand, std::condition_variable::wait() blocks the current thread, and that thread is waiting in the point of suspending until some another thread is calling a notify..() function
Why is it necessary to use while() with std::condition_variable::wait()
wait may return whether ready is true or not. If we want to proceed only when ready is true, then we must check it, and continue waiting in case it isn't. A loop is a convenient control structure for repeating an operation until a condition is satisfied.
why wait() may return seemingly spuriously
Because the standard says that it may:
Effects:
Atomically calls lock.unlock() and blocks on *this.
When unblocked, calls lock.lock( (possibly blocking on the lock), then returns.
The function will unblock when signaled by a call to notify_one() or a call to notify_all(), or spuriously.
#include <iostream>
#include<thread>
#include <initializer_list>
#include <vector>
#include <future>
#include <time.h>
using namespace std;
class Gadget{
public:
Gadget(){
flag_ = false;
cout<<"Creating new Gadgets"<<endl;
}
void wait(){
while(flag_==false){
cout<<"waiting here...."<<endl;
this_thread::sleep_for(chrono::milliseconds(1000));
}
}
void wake(){
flag_ = true;
}
private:
volatile bool flag_;
};
I am trying to make two threads and one thread will sleep for 1 sec after checking the flag value. As i have made flag volatile it should change at some point. But the program is waiting infinitely.
int main() {
Gadget g;
thread t(&Gadget::wait,g);
thread s(&Gadget::wake,g);
t.join();
s.join();
cout<<"Ending the program "<<endl;
return 0;
}
volatile isn't for variables that are changed by the program itself. It's for variables that changes outside the program's control - like if it's directly connected to hardware.
Your main problem is however that you pass g by value so the two threads are working on different copies of your original g.
So, change to
std::atomic<bool> flag_;
and
thread t(&Gadget::wait, &g);
thread s(&Gadget::wake, &g);
Also worth mentioning: The two methods will not necessarily run in the order you start them, so waiting here.... may or may not show up.
Edit:
As mentioned in the comments: When waiting for a condition you should usually use a std::condition_variable. I've made an example of how that could look. I've also moved the starting of the threads into Gadget which makes it more obvious which object the thread is working on.
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
class Gadget {
public:
Gadget() { std::cout << "Creating new Gadget\n"; }
// new interface for starting threads
std::thread start_wait() { return std::thread(&Gadget::wait, this); }
std::thread start_wake() { return std::thread(&Gadget::wake, this); }
private:
void wait() {
std::unique_lock<std::mutex> ul(mutex_);
std::cout << "wait: waiting here...\n";
// Read about "spurious wakeup" to understand the below:
while(not flag_) cond_.wait(ul);
// or:
// cond_.wait(ul, [this] { return flag_; });
std::cout << "wait: done\n";
}
void wake() {
// simulate some work being done for awhile
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
{ // lock context start
std::lock_guard<std::mutex> lg(mutex_);
flag_ = true;
std::cout << "wake: notifying the waiting threads\n";
} // lock context end
// notify all waiting threads
cond_.notify_all();
}
std::condition_variable cond_;
std::mutex mutex_;
bool flag_ = false; // now guarded by a mutex instead
};
int main() {
Gadget g;
// start some waiting threads
std::vector<std::thread> threads(16);
for(auto& th : threads) th = g.start_wait();
// and one that wakes them up
auto th_wake = g.start_wake();
for(auto& th : threads) th.join();
th_wake.join();
std::cout << "Ending the program\n";
}
I'm trying to write a program which uses c++11 threads functionality in order to spawn multiple threads, the main thread must wait for each spawned thread to be finished, and all spawned threads must run in parallel. I've come up with the following approach:
#include <iostream>
#include <stdio.h>
#include <thread>
#include <condition_variable>
#include <mutex>
using namespace std;
class Producer
{
public:
Producer(int a_id):
m_id(a_id),
m_running(false),
m_ready(false),
m_terminate(false)
{
m_id = a_id;
m_thread = thread(&Producer::run, this);
while (!m_ready) {}
}
~Producer() {
terminate();
m_thread.join();
}
void wait() {
unique_lock<mutex> lock(m_waitForRunFinishMutex);
m_cond.wait(lock);
// avoid spurious wake up
if (m_running) {
wait();
}
lock.unlock();
cout << "wait exit " << m_id << endl;
}
void start() {
m_running = true;
m_cond.notify_all();
}
void terminate() {
start();
m_terminate = true;
}
void run() {
m_ready = true;
do {
unique_lock<mutex> lock(m_mutex);
while (!m_running) {
m_cond.wait(lock);
}
if (!m_terminate) {
cout << "running thread: " << m_id << endl;
}
m_running = false;
m_cond.notify_all();
} while (!m_terminate);
}
private:
int m_id;
bool m_running;
bool m_ready;
bool m_terminate;
thread m_thread;
mutex m_mutex;
mutex m_waitForRunFinishMutex;
condition_variable m_cond;
};
The program runs fine when testing with just one thread, i.e the following program:
int main()
{
Producer producer1(1);
producer1.start();
producer1.wait();
return 0;
}
Results in the following output:
running thread: 1
wait exit: 1
However if I test the program with 2 thread, e.g:
int main()
{
Producer producer1(1);
Producer producer2(2);
producer1.start();
producer2.start();
producer1.wait();
producer2.wait();
return 0;
}
I get the following output:
running thread: 2
running thread: 1
wait exit 1
It seems producer2 never get notified (in producer2.wait()), and therefore the program never finishes. Hopefully somebody can point out what I'm missing here.
Thanks everybody for the help in addressing the problem. Eventually the root cause of the problem is described in point (3) of the accepted answer. I've solved this by correcting the wait function as follows:
void wait() {
unique_lock<mutex> lock(m_waitForRunFinishMutex);
while (m_running) {
m_cond.wait(lock);
}
lock.unlock();
}
Here's a quick collection of issues from a glance.
wait() is recursive without unlocking its unique lock (as per the comment from Detonar)
while (!m_ready) {} Is not in a memory barrier (try compiling with some optimization and see what happens!)
If the worker thread completes before wait() is called; there is no check performed before waiting on the condition variable. Since the worker thread is complete; it will never get woken. Clearly you must check to see if the thread can get woken up within the mutex before waiting on the condition variable.
I've implemented a simple Producer-Consumer message queue.
#include <chrono>
#include <iostream>
#include <thread>
#include <mutex>
#include <deque>
#define MESSAGE_QUIT 1
struct MessageQueue
{
std::deque<int> message_ids;
std::mutex mutex;
std::condition_variable condition_variable;
};
void SleepFor(int time_in_millis)
{
std::this_thread::sleep_for(std::chrono::milliseconds(time_in_millis));
}
void ProcessMessage(int message_id)
{
std::cout << "Processing Message #" << message_id << '\n';
}
void Producer(MessageQueue *messages)
{
for (int message_id = 10; message_id >= MESSAGE_QUIT; --message_id) {
std::unique_lock<std::mutex> guard(messages->mutex);
messages->message_ids.push_back(message_id);
guard.unlock();
messages->condition_variable.notify_one();
SleepFor(200);
}
}
void Consumer(MessageQueue *messages)
{
int next_message_id = -1;
while (next_message_id != MESSAGE_QUIT) {
std::unique_lock<std::mutex> guard(messages->mutex);
messages->condition_variable.wait(guard);
next_message_id = messages->message_ids.front();
messages->message_ids.pop_front();
guard.unlock();
ProcessMessage(next_message_id);
}
}
int main()
{
MessageQueue messages;
std::thread producer_thread(&Producer, &messages);
std::thread consumer_thread(&Consumer, &messages);
producer_thread.join();
consumer_thread.join();
}
The race condition: in some cases, the condition variable is calling notify_one() in the producer thread while it is not in the waiting state in the consumer thread. How would you solve this? I am not considering the case of spurious waking for now.
Condition variables can spuriously wake up.
messages->condition_variable.wait(guard)
So don't do this. There are other reasons to not do this, including the fact that you can wait on a condition variable when there is data ready.
messages->condition_variable.wait(guard, [&]{return !messages->message_ids().empty();)
This won't wait if there are already messages in the queue. It also deals with spurious wakeups.
What is boost:barrier, how to use this kind of boost method. Could you give me a clear example since I found the examples on the following:
bool wait()
{
boost::mutex::scoped_lock lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0)
{
m_generation++;
m_count = m_threshold;
m_cond.notify_all();
return true;
}
while (gen == m_generation)
m_cond.wait(lock);
return false;
}
In the above codes: m_cond.notify_all();is to enter into other waiting threads?
Could you tell me clearly about barrier functionality? Thank you.
notify_all, notified awaiting threads.
A barrier is a simple concept. Also known as a rendezvous, it is a
synchronization point between multiple threads. The barrier is
configured for a particular number of threads (n), and as threads
reach the barrier they must wait until all n threads have arrived.
Once the n-th thread has reached the barrier, all the waiting threads
can proceed, and the barrier is reset.
Simple example. value of the current will be outputed only when 3 threads call wait function on barrier.
#include <boost/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <boost/bind.hpp>
#include <boost/atomic.hpp>
boost::mutex io_mutex;
void thread_fun(boost::barrier& cur_barier, boost::atomic<int>& current)
{
++current;
cur_barier.wait();
boost::lock_guard<boost::mutex> locker(io_mutex);
std::cout << current << std::endl;
}
int main()
{
boost::barrier bar(3);
boost::atomic<int> current(0);
boost::thread thr1(boost::bind(&thread_fun, boost::ref(bar), boost::ref(current)));
boost::thread thr2(boost::bind(&thread_fun, boost::ref(bar), boost::ref(current)));
boost::thread thr3(boost::bind(&thread_fun, boost::ref(bar), boost::ref(current)));
thr1.join();
thr2.join();
thr3.join();
}