Blocking condition variables
{ Please limit your text to fit within 80 columns, preferably around 70,
so that readers don't have to scroll horizontally to read each line.
This article has been reformatted manually by the moderator. -mod }
Hello,
I have written a program, which will describe a workflow synchronized by
condition variables. The idea is simple. Two workers notify the boss
(notify_one), when their step of work is done. As soon as the boss gets
the two notifications, he notifys (notify_all) both worker, so that they
can proceed.
These interaction will take place two times. The first time, the workers
have to prepare their work. The second time, the workers have to do their
work.
In order to get right number of notifications, the boss use atomic
variables.
And here is the program.
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <random>
#include <thread>
// Boss -> Worker
bool startWork, goHome;
std::mutex startWorkMutex, goHomeMutex;
std::condition_variable boss2WorkerCondVariable;
// Worker -> Boss
std::mutex preparedMutex, doneMutex;
std::condition_variable worker2BossCondVariable;
std::atomic_int preparedCount, doneCount;
int getRandomTime(int start, int end){
std::random_device seed;
std::mt19937 engine(seed());
std::uniform_int_distribution<int> dist(start,end);
return dist(engine);
};
class Worker{
public:
Worker(std::string n):name(n){};
void operator() (){
// prepare the work and notfiy the boss
int prepareTime= getRandomTime(500,2000);
std::this_thread::sleep_for(std::chrono::milliseconds(prepareTime));
preparedCount++;
std::cout << name << ": " << prepareTime << std::endl;
worker2BossCondVariable.notify_one();
// { scope seems to be necessary
// wait for the start notification of the boss
std::unique_lock<std::mutex> startWorkLock( startWorkMutex );
boss2WorkerCondVariable.wait( startWorkLock,[]{ return startWork;});
// }
// do the work and notify the boss
int workTime= getRandomTime(200,400);
std::this_thread::sleep_for(std::chrono::milliseconds(workTime));
doneCount++;
std::cout << name << ": " << workTime << std::endl;
worker2BossCondVariable.notify_one();
// { scope seems to be necessary
// wait for the go home notification of the boss
std::unique_lock<std::mutex> goHomeLock( goHomeMutex );
boss2WorkerCondVariable.wait( goHomeLock,[]{ return goHome;});
// }
}
private:
std::string name;
};
int main(){
Worker worker1(" Worker1");
std::thread worker1Work(worker1);
Worker worker2(" Worker2");
std::thread worker2Work(worker2);
std::cout << "BOSS: PREPARE YOUR WORK.\n " << std::endl;
// waiting for the worker
preparedCount.store(0);
std::unique_lock<std::mutex> preparedUniqueLock( preparedMutex );
worker2BossCondVariable.wait(preparedUniqueLock,[]{ return preparedCount == 2; });
// notify the worker about the begin of the work
startWork= true;
std::cout << "\nBOSS: START YOUR WORK. \n" << std::endl;
boss2WorkerCondVariable.notify_all();
// waiting for the worker
doneCount.store(0);
std::unique_lock<std::mutex> doneUniqueLock( doneMutex );
worker2BossCondVariable.wait(doneUniqueLock,[]{ return doneCount == 2; });
// notify the worker about the end of the work
goHome= true;
std::cout << "\nBOSS: GO HOME. \n" << std::endl;
boss2WorkerCondVariable.notify_all();
worker1Work.join();
worker2Work.join();
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
In case I'm executing the program, the condition variables will block:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
BOSS: PREPARE YOUR WORK.
Worker1: 658
Worker2: 1836
BOSS: START YOUR WORK.
Worker1: 270
^C
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
In case I'm using the artificial scope in the the functor (look at the
source code), the program behave in the expected way.
BOSS: PREPARE YOUR WORK.
Worker1: 650
Worker2: 1507
BOSS: START YOUR WORK.
Worker1: 201
Worker2: 364
BOSS: GO HOME.
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
This behaviour is happening with GCC4.6 and also with GCC4.7. I have no
idea why is is necessary to control the lifetime of the unique_lock in
den body of the functor.
Kindly regards from Rottenburg,
Rainer Grimm
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]