boost::threadpool::pool::wait() doesn't stop - c++

I was trying to write some Task-Management class with C++ boost::threadpool, condition_variable and mutex. It seems the program will stop at boost::threadpool::pool::wait(), but I don't know why this happens.
#include <boost/threadpool.hpp>
#include <condition_variable>
#include <iostream>
#include <mutex>
using namespace std;
enum {
Running,
Stopped,
Exiting
};
class C {
private:
int m_iStatus;
mutex m_mtx;
condition_variable m_cond;
boost::threadpool::pool m_tp;
public:
C() : m_iStatus(Stopped), m_tp(8) {}
void Start();
void Exit();
private:
bool Check();
void Dispatcher();
};
bool C::Check()
{
unique_lock<mutex> lk(m_mtx);
if (m_iStatus == Stopped)
m_cond.wait(lk);
if (m_iStatus == Exiting)
return false;
else
return true;
}
void C::Dispatcher()
{
if (!Check())
return;
unique_lock<mutex> lk(m_mtx);
// do something...
cout << "." << endl;
m_tp.schedule(bind(&C::Dispatcher, this));
}
void C::Start()
{
unique_lock<mutex> lk(m_mtx);
m_iStatus = Running;
m_tp.schedule(bind(&C::Dispatcher, this));
}
void C::Exit()
{
unique_lock<mutex> lk(m_mtx);
m_iStatus = Exiting;
m_cond.notify_all(); /* notify those waiting on m_cond */
m_tp.wait(); /* went wrong here */
}
int main()
{
C c;
c.Start();
/* wait for a moment */
Sleep(1000);
/* then call Exit */
c.Exit();
return 0;
}

You enter the wait call while still holding the mutex. This will prevent other thread's from completing their work.
In your particular case, the m_cond condition variable is waiting on that same mutex, so the call to m_cond.wait(lk); will be unable to return as long as the mutex is still being held by the other thread.
One solution to this would be to relinquish the lock on the mutex between notifying the condition variable and waiting for the thread pool to complete:
{
unique_lock<mutex> lk(m_mtx);
m_iStatus = Exiting;
m_cond.notify_all(); /* notify those waiting on m_cond */
} // lock on m_mtx gets released here
m_tp.wait(); /* this should run fine now */

Related

How to wait for multiple threads to finish (with c++11 threads)?

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.

Wake thread and exit from sleep

I have a singleton class which looks something like:
//Test.h
class Test
{
private:
static std::mutex mtx;
static std::condition_variable cv;
static bool end;
static void DoSomethingThread();
static void SomeOtherFunction();
public:
static void Start();
}
//Test.cpp
std::mutex Test::mtx;
std::condition_variable Test::cv;
bool Test::end = false;
void Test::Start()
{
std::thread t_thread(Test::DoSomethingThread);
while(a) {
if (b) {
// End thread.
std::unique_lock<std::mutex> lock(mtx);
Test::end = true;
Test::cv.notify_one();
t_thread.join();
Test::SomeOtherFunction();
// Restart thread.
Test::end = false;
t_thread = std::thread(Test::DoSomethingThread);
}
...
}
}
void Test::DoSomethingThread()
{
std::unique_lock<std::mutex> lock(mtx);
while (1) {
//Do some work here.
Test::cv.wait_for(lock, std::chrono::seconds(1000), []() { return Test::end; });
if (Test::end) { break; }
}
}
I found this code on this page and to be honest dont really know how this works. But the guy had the same problem as me and I thought it would work for my case to, but it didnt.
So what I currently have is have a thread t_thread which runs forever, it does some work and then sleeps for 1000 seconds and all over again. What I need is some way to wake this thread up from sleep and exit it. So SomeOtherFunction() can do its work and then restart the thread.
Why doesnt this code works, and how can I make it work?
I went back to original post and did:
if (b) {
{
// End thread.
std::unique_lock<std::mutex> lock(mtx);
Test::end = true;
Test::cv.notify_one();
}
t_thread.join();
Test::SomeOtherFunction();
// Restart thread.
Test::end = false;
t_thread = std::thread(Test::DoSomethingThread);
}
And it works now. Thanks anyway.

Threaded timer, interrupting a sleep (stopping it)

I'm wanting a reasonably reliable threaded timer, so I've written a timer object that fires a std::function on a thread. I would like to give this timer the ability to stop before it gets to the next tick; something you can't do with ::sleep (at least I don't think you can).
So what I've done is put a condition variable on a mutex. If the condition times out, I fire the event. If the condition is signalled the thread is exited. So the Stop method needs to be able to get the thread to stop and/or interrupt its wait, which I think is what it's doing right now.
There are problems with this however. Sometimes the thread isn't joinable() and sometimes the condition is signalled after its timeout but before it's put into its wait state.
How can I improve this and make it robust?
The following is a full repo. The wait is 10 seconds here but the program should terminate immediately as the Foo is created and then immediately destroyed. It does sometimes but mostly it does not.
#include <atomic>
#include <thread>
#include <future>
#include <sstream>
#include <chrono>
#include <iostream>
class Timer
{
public:
Timer() {}
~Timer()
{
Stop();
}
void Start(std::chrono::milliseconds const & interval, std::function<void(void)> const & callback)
{
Stop();
thread = std::thread([=]()
{
for(;;)
{
auto locked = std::unique_lock<std::mutex>(mutex);
auto result = terminate.wait_for(locked, interval);
if (result == std::cv_status::timeout)
{
callback();
}
else
{
return;
}
}
});
}
void Stop()
{
terminate.notify_one();
if(thread.joinable())
{
thread.join();
}
}
private:
std::thread thread;
std::mutex mutex;
std::condition_variable terminate;
};
class Foo
{
public:
Foo()
{
timer = std::make_unique<Timer>();
timer->Start(std::chrono::milliseconds(10000), std::bind(&Foo::Callback, this));
}
~Foo()
{
}
void Callback()
{
static int count = 0;
std::ostringstream o;
std::cout << count++ << std::endl;
}
std::unique_ptr<Timer> timer;
};
int main(void)
{
{
Foo foo;
}
return 0;
}
See my comment. You forgot to implement the state of the thing the thread is waiting for, leaving the mutex nothing to protect and the thread nothing to wait for. Condition variables are stateless -- your code must track the state of the thing whose change you're notifying the thread about.
Here's the code fixed. Notice that the mutex protects stop, and stop is the thing the thread is waiting for.
class Timer
{
public:
Timer() {}
~Timer()
{
Stop();
}
void Start(std::chrono::milliseconds const & interval,
std::function<void(void)> const & callback)
{
Stop();
{
auto locked = std::unique_lock<std::mutex>(mutex);
stop = false;
}
thread = std::thread([=]()
{
auto locked = std::unique_lock<std::mutex>(mutex);
while (! stop) // We hold the mutex that protects stop
{
auto result = terminate.wait_for(locked, interval);
if (result == std::cv_status::timeout)
{
callback();
}
}
});
}
void Stop()
{
{
// Set the predicate
auto locked = std::unique_lock<std::mutex>(mutex);
stop = true;
}
// Tell the thread the predicate has changed
terminate.notify_one();
if(thread.joinable())
{
thread.join();
}
}
private:
bool stop; // This is the thing the thread is waiting for
std::thread thread;
std::mutex mutex;
std::condition_variable terminate;
};

How to start a thread when an event occurs and close their handles crrectly

I'm making a service, which is listening on a logon event. If this event occurs, my application should start a new thread, which will do the work.
My question is, how can i start a new thread every time a logon event occurs, and close it's handle correctly if the thread is done working. My problem is, that i don't know how many logon event will occur, so i can't user WaitForMultipleObjects because it's first parameter is the number of threads it should wait for.
while ( WaitForSingleObject( ghSvcStopEvent, 0 ) != WAIT_OBJECT_0 )
{
DWORD dwEventFlags;
BOOL bRes;
// WTSWaitSystemEvent waits until a logon event ocurs
bRes = WTSWaitSystemEvent( WTS_CURRENT_SERVER_HANDLE, WTS_EVENT_LOGON, &dwEventFlags );
if ( dwEventFlags == WTS_EVENT_NONE )
{
ShowErrorText( "Cancelling waiting for logon event. Service shutting down.", 0, true );
}
if ( bRes )
{
// Someone has logged on
HANDLE hThread = CreateThread( NULL, 0, ServiceWorkerThread, NULL, 0, &dwThreadID );
}
else
{
ShowErrorText( "WTSWaitSystemEvent failed.", GetLastError(), true );
}
}//while
Could someone help me?
Thanks!
If you can use C++11 (starting VS2010), you an use condition variable that will do the job for you
The idea of a condition variable is:
one variable that allows threads to comunicate together.
if you notify it, you send a signal to other threads pluged on it
if you do cv.wait(...) on it, you wait for other threads to signal that sonething has happenend and then you test your condition again.
Here is an example
Server.h
#include <condition_variable>
#include <mutex>
class CServer
{
std::condition_variable & cv;
std::mutex & mut;
bool & flag;
public:
~CServer(void);
CServer::CServer(std::condition_variable & cv,
std::mutex & mut,
bool & flag);
CServer::CServer(CServer &);
int Notify();
int DisplayNotification();
std::condition_variable & getCondVar(){return cv;}
std::mutex & getMutex(){return mut;}
bool & getFlag(){return flag;}
};
Server.cpp
#include "Server.h"
#include <iostream>
using namespace std;
CServer::~CServer(void)
{
}
CServer::CServer(std::condition_variable & cv_,
std::mutex & mut_,
bool & flag_):
cv(cv_),
mut(mut_),
flag(flag_)
{
}
CServer::CServer(CServer &toCopy):
cv(toCopy.getCondVar()),
mut(toCopy.getMutex()),
flag(toCopy.getFlag())
{
flag=false;
cout<<"Copy constructor"<<std::endl;
}
int CServer::Notify()
{
{
std::lock_guard<std::mutex> lk(mut);
flag=true;
std::cout << "ready for notfication"<<endl;
}
cv.notify_one();
return 0;
}
int CServer::DisplayNotification()
{
// wait for the worker
{
std::unique_lock<std::mutex> lk(mut);
cv.wait(lk, [this]{return this->getFlag();});
}
cout<<"Notification displayed"<<endl;
return 0;
}
Client.h
#include <chrono>
#include "Server.h"
class CClient
{
CServer & serv;
std::chrono::seconds sleepTime;
bool finishedWork;
public:
CClient(CServer & serv,
std::chrono::seconds sleepTime);
~CClient(void);
int work();
};
Client.cpp
#include "Client.h"
#include <thread>
using namespace std;
CClient::CClient(CServer & serv_,
std::chrono::seconds sleepTime_):
serv(serv_),
sleepTime(sleepTime_),
finishedWork(false)
{
}
CClient::~CClient(void)
{
}
int CClient::work()
{
this_thread::sleep_for(sleepTime);
finishedWork=true;
serv.Notify();
return 0;
}
Main.cpp
#include "Client.h"
#include <thread>
using namespace std;
int main()
{
std::chrono::seconds sleepTime=std::chrono::seconds(10);
//create client and server
condition_variable cv;
mutex mut;
bool flag=false;
CServer serv(cv,mut, flag);
CClient cli(serv,sleepTime);
//thread with the server
thread thServ(&CServer::DisplayNotification,serv);
////thread with the client
thread thCli (&CClient::work,cli);
////join threads
thServ.join();
thCli.join();
return 0;
}
Ask me if you have any questions,
Hope that helps

Pthread locking

I have created MutexCondition class like this
/*MutexCondtion.h file*/
#ifndef MUTEXCONDITION_H_
#define MUTEXCONDITION_H_
#include <pthread.h>
#include <stdio.h>
class MutexCondition {
private:
bool init();
bool destroy();
protected:
pthread_mutex_t m_mut;
pthread_cond_t m_con;
public:
MutexCondition(){
init();
}
virtual ~MutexCondition(){
destroy();
}
bool lock();
bool unLock();
bool wait();
bool signal();
};
#endif /* MUTEXCONDITION_H_ */
MutexCondtion.cpp file
#include "MutexCondition.h"
bool MutexCondition::init(){
printf("MutexCondition::init called\n");
pthread_mutex_init(&m_mut, NULL);
pthread_cond_init(&m_con, NULL);
return true;
}
bool MutexCondition::destroy(){
pthread_mutex_destroy(&m_mut);
pthread_cond_destroy(&m_con);
return true;
}
bool MutexCondition::lock(){
pthread_mutex_lock(&m_mut);
return true;
}
bool MutexCondition::unLock(){
pthread_mutex_unlock(&m_mut);
return true;
}
bool MutexCondition::wait(){
pthread_cond_wait(&m_con, &m_mut);
return true;
}
bool MutexCondition::signal(){
pthread_cond_signal(&m_con);
return true;
}
And I created a WorkHandler which extends the MutexCondition
#ifndef WORKHANDLER_H_
#define WORKHANDLER_H_
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <pthread.h>
#include <stdio.h>
#include <list>
#include "MutexCondition.h"
#include "Work.h"
using namespace::std;
class WorkHandler: MutexCondition {
private:
int m_maxThreads;
queue<Work*> m_workQueue;
list<pthread_t*> m_workThreadList; //Just thread IDs
pthread_t **m_workThreads;
void workLoop();
bool initThreads();
void insertWork(Work *work);
Work* getWork();
protected:
static void* runWorkThread(void* delegate);
public:
WorkHandler(int maxThreads);
virtual ~WorkHandler();
};
#endif /* WORKHANDLER_H_ */
WorkHandler.cpp file
#include "WorkHandler.h"
WorkHandler::WorkHandler(int maxThreads) {
// TODO Auto-generated constructor stub
m_maxThreads = maxThreads;
initThreads();
}
WorkHandler::~WorkHandler() {
// TODO Auto-generated destructor stub
}
void* WorkHandler::runWorkThread(void *delegate){
printf("WorkHandler::runWorkThread called\n");
WorkHandler *ptr = reinterpret_cast<WorkHandler*>(delegate);
ptr->workLoop();
return NULL;
}
void WorkHandler::workLoop(){
printf("WorkHandler::workLoop called\n");
//WorkHandler *ptr = reinterpret_cast<WorkHandler*>(delegate);
while(1){
Work *work = getWork();
}
}
bool WorkHandler::initThreads(){
for(int i=0; i < m_maxThreads; i++){
pthread_t *thread(new pthread_t);
m_workThreadList.push_back(thread);
if(pthread_create(thread, NULL, runWorkThread, reinterpret_cast<void *>(this))!=0){
perror("InitThreads, pthread_create error \n");
return false;
}
pthread_detach(*thread);
}
return true;
}
void WorkHandler::insertWork(Work* w){
printf("WorkHandler::Thread %d insertWork locking\n", pthread_self());
lock();
printf("WorkHandler::insertWork Locked and inserting int queue \n");
m_workQueue.push(w);
signal();
unLock();
}
Work* WorkHandler::getWork(){
printf("WorkHandler::getWork locking\n");
lock();
printf("WorkHandler::getWork locked\n");
while(m_workQueue.empty()){//Need while instead of If
printf("WorkHandler::getWork waiting...\n");
wait();
}
Work *work = m_workQueue.front();
printf("WorkHandler::getWork got a job\n");
m_workQueue.pop();
unLock();
return work;
}
The problem is that I have locked the mutex variable in the getWork() function like this
printf("WorkHandler::getWork locking\n");
lock();
printf("WorkHandler::getWork locked\n");
However, if I see the log statements then all threads printed these two log statements and I think this is a problem. I am not putting anything into the queue so the first thread should wait the condition variable to be signaled and it works ok. But how come other thread can enter the area behind the lock although the first thread locked and has not called the unlock() function.
I was wondering if this is working correctly. Pleas let me know if you guys can see anything I need to fix. Thanks in advance.
The reason is that that when a thread waits on a condition variable the mutex is unlocked.
This is expected behavior.
When the condition variable is signaled the thread is not released to run until the lock is re-acquired.
If you change the function to this:
Work* WorkHandler::getWork(){
// Remoed this as it is non-determinstic when it will be printed.
lock();
printf("WorkHandler::getWork locked\n");
while(m_workQueue.empty()){//Need while instead of If
printf("WorkHandler::getWork waiting...\n");
wait();
printf("WorkHandler::getWork waiting DONE\n"); // Added this.
}
Work *work = m_workQueue.front();
printf("WorkHandler::getWork got a job\n");
m_workQueue.pop();
unLock();
return work;
}
If you then created three threads I would expect:
WorkHandler::getWork locked
WorkHandler::getWork waiting...
WorkHandler::getWork locked;
WorkHandler::getWork waiting...
WorkHandler::getWork locked
WorkHandler::getWork waiting...
For each call to signal I would expect:
WorkHandler::Thread %d insertWork locking
WorkHandler::insertWork Locked and inserting int queue
WorkHandler::getWork waiting DONE
WorkHandler::getWork got a job
No matter how fast you call signal I would always expect to see these two printed in order.
Because the thread is not released from the condition variable until it has re-acquired the lock.
Note you may see.
WorkHandler::Thread %d insertWork locking
WorkHandler::insertWork Locked and inserting int queue
WorkHandler::getWork locked // A previously released thread finishes and steals
// the job before the signalled thread can aquire the lock.
WorkHandler::getWork got a job
WorkHandler::getWork waiting DONE // Now the released thread just goes back to waiting.
WorkHandler::getWork waiting...