I've created a custom ThreadPool which starts a number of win32 threads with _beginthreadex(). The threads are running a simple loop that attempts to dequeue tasks from a blocking queue, but sometimes I need to stop the threads and if they're blocked on Dequeue then I don't know how to get the threads out of that blocking state.
void ThreadPool::Loop()
{
while(_running)
{
try
{
// Attempts to dequeue a task and run it
_taskQueue.Dequeue()->Run();
}
catch(BlockingQueueTerminate&)
{
// Eat the exception and check the running flag
continue;
}
}
}
My idea was to enqueue the same number of special tasks (let's call them "termination tasks") as there are threads in the pool and each "termination task" will call _endthreadex(0) in order to exit the thread. If there are other tasks in the blocking queue, then I won't really care because as soon as I dequeue a task, I will run it and I will check the _running flag to determine if the thread needs to dequeue any more tasks.
void TerminationTask::Run()
{
_endthreadex(0);
}
I have several concerns about this approach; mainly, if I processed a non-terminating task and the _running flag is set to false, then my thread will not call _endthreadex(0) when it exits the loop. I was wondering if I could call _endthreadex(0) at the end of the loop like this:
void ThreadPool::Loop()
{
while(_running)
{
try
{
// Attempts to dequeue a task and run it
_taskQueue.Dequeue()->Run();
}
catch(BlockingQueueTerminate&)
{
// Eat the exception and check the running flag
continue;
}
}
_endthreadex(0);
}
Will this cause a conflict with my TerminationTask or will the thread exit the loop directly after executing TerminationTask::Run() (i.e. it won't call _endthreadex(0) twice)? Furthermore, is there a better approach than this?
Calling _endthreadex(0) at the end of the thread method is fine. It is also optional. If you just leave the thread method normally, then _endthreadex(0) is called for you.
You can call _endthread or _endthreadex explicitly to terminate a thread; however, _endthread or _endthreadex is called automatically when the thread returns from the routine passed as a parameter to _beginthread or _beginthreadex.ref
Sending a termination task is the correct way to get a blocked thread pool thread to unblock and quit.
So, to summarise:
Your strategy is good and the implementation of TerminationTask::Run is correct.
You can remove the harmless call to _endthreadex(0) at the end of ThreadPool::Loop.
Putting a temination task in the Queue is correct. I would try a different approach to handling it, though:
class TerminateThreadNow {};
void TerminationTask::Run()
{
throw TerminateThreadNow();
}
void ThreadPool::Loop()
{
while(_running)
{
try
{
// Attempts to dequeue a task and run it
_taskQueue.Dequeue()->Run();
}
catch(TerminateThreadNow&)
{
_running = false;
}
catch(BlockingQueueTerminate&)
{
// Eat the exception and check the running flag
}
}
}
Related
I have two threads. The first creates a Logic object, detaching a second thread to spin, blocking on OpenSSL socket to receive messages:
struct Logic
{
Logic()
{
std::thread t1(&Logic::run, this);
t1.detach();
}
void run()
{
while(true)
{
// Gets data from SSL (blocking socket)
// Processes data
// Updates timestamp
}
}
uint64_t timestamp;
};
The first thread returns, enters a while loop and continually checks if the detached thread is still running (or whether its blocked permanently).
while(true)
{
Logic logic();
while(true)
{
if(timestamp_not_updated)
{
break; // Break, destroy current Logic object and create another
}
}
}
If the timestamp stops being updated, the inner while loop breaks, causing the Logic object to be destroyed and a new one created.
When this restart behaviour triggers I get a seg fault. thread apply all bt shows 3 threads, not 2. The original detached thread (blocking on OpenSSL) still exists. I thought this would get destroyed due to the object.
How do I stop a detached thread which is blocking/waiting on a resource, so I can restart my class? I need the blocking behaviour because I don't have anything else to do (besides receive the packet) and it's better for performance, than to keep calling in to OpenSSL.
I have a worker thread handling some time-consuming task. For some reason, it starts using _beginthreadex and condition_variable to wait for tasks. The code looks like:
void MyThread::worker()
{
while(true)
{
unique_lock<mutex> ulk(mut_);
cv_.wait(ulk, [this](){return !this->TasksQueueEmpty() || this->ShouldTerminate();});
if(ShouldTerminate())
break;
auto task = GetTaskFromQueue();
ulk.unlock();
task.Run();
}
}
void MyThread::terminate()
{
unique_lock<mutex> ulk(mut_);
SetTerminate();
cv_.notify_one();
}
Here task.Run() is a very time-consuming job. I would like to terminate the worker any time I want without waiting. And it seems that TerminateThread may cause some resource handling exception. Is there a workaround?
The terminate() function should additionally set a boolean flag that the task.run() function should check frequently enough to make the stopping quick.
Terminatethread() can leave the program state inconsistent. Mutexes that were held by the thread will be left locked and memory is left allocated and open files arent closed etc.
I have used below structure to create a threadpool, now the question is how do I let all the preallocate threads end properly?
std::vector<pthread_t> preallocatedThreadsPool; // threadpool
std::queue<int> tcpQueue; // a queue to hold my task
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition_var = PTHREAD_COND_INITIALIZER;
void* threadFunctionUsedByThreadsPool(void *arg);
main () {
preallocatedThreadsPool.resize(preallocatThreadsNumber);
for(pthread_t i : preallocatedThreadsPool) {
pthread_create(&i, NULL, threadFunctionUsedByThreadsPool, NULL);
}
pthread_mutex_lock(&mutex); // one thread mess with the queue at one time
tcpQueue.push(task);
pthread_cond_signal(&condition_var);
pthread_mutex_unlock(&mutex);
}
void* threadFunctionUsedByThreadsPool(void *arg) {
while (true) {
pthread_mutex_lock(&mutex);
if (tcpQueue.empty()) { // can't get work from the queue then just wait
pthread_cond_wait(&condition_var, &mutex); // wait for the signal from other thread to deal with client otherwise sleep
task = tcpQueue.front();
tcpQueue.pop();
}
pthread_mutex_unlock(&mutex);
if (task) {
// do task
}
}
return NULL;
}
I have been searching for days for this problem still can not find a decent solution, the closest one I have tried is , when the program wants to quit, push a special item into the queue, then inside threadFunctionUsedByThreadsPool, when detecting such item, I will call pthread_join, however, when I using gdb tool to debug it , those pre-allocated threads are still there, anyone could help, better with some code, for example, how do I modify the threadFunctionUsedByThreadsPool, so that I can quit all the pre-allocated threads properly?
Thanks so much!!!
TLDR: You just need a thread-safe variable that all threads can check for an exit condition in between work items. Use pthread_join to wait for a thread to exit.
First, let's get the while loop in your thread function correct with respect to condition variables.
Instead of this:
pthread_cond_wait(&condition_var, &mutex); // wait for the signal from other thread to deal with client otherwise sleep
task = tcpQueue.front();
tcpQueue.pop();
Check the state of the queue before before and after waking up on the condition variable. Spurious wake up is a real thing and there's no guarantee another thread didn't wake up and grab the last work item. You definitely don't want to be popping from an empty queue.
Better:
while (tcpQueue.empty()) {
pthread_cond_wait(&condition_var, &mutex); // wait for the signal from other thread to deal with client otherwise sleep
}
task = tcpQueue.front();
tcpQueue.pop();
With that addressed, we can introduce a new global bool that represents the stop condition:
bool stopCondition = false;
Whenever we want to tell all the threads in the pool to stop, we can set stopCondition to true and signal the condition var to alert all threads of a state change. Reading or writing stopCondition should be done under a lock. (I suppose you could also use std::atomic<bool>)
Putting it all together, your thread function becomes this:
void* threadFunctionUsedByThreadsPool(void* arg) {
pthread_mutex_lock(&mutex);
while (!stopCondition) {
// wait for a task to be queued
while (tcpQueue.empty() && !stopCondition) {
pthread_cond_wait(&condition_var, &mutex); // wait for the signal from other thread to deal with client otherwise sleep
}
if (stopCondition == false) {
task = tcpQueue.front();
tcpQueue.pop();
// exit lock while operating on a task
pthread_mutex_unlock(&mutex);
if (task) {
// do task
}
// re-acquire the lock
pthread_mutex_lock(&mutex);
}
}
// release the lock before exiting the function
pthread_mutex_unlock(&mutex);
return NULL;
}
And then a helper function to signal all the threads to exit and also waits for each thread to stop. notice that we're using pthread_cond_broadcast to notify all threads to wake up from their condition variable wait instead of pthread_cond_signal which only wakes up one thread.
void stopThreadPool()
{
// signal all threads to exit after they finish their current work item
pthread_mutex_lock(&mutex);
stopCondition = true;
pthread_cond_broadcast(&condition_var); // notify all threads
pthread_mutex_unlock(&mutex);
// wait for all threads to exit
for (auto& t : preAllocatedThreadsPool) {
pthread_join(t, nullptr);
}
preAllocatedThreadsPool.clear();
}
One last bug that I just caught - your main isn't property initializing your preAllocatedThreadsPool vector like you think it is. You're making a copy of the pthread_t, instead of using the handle actually in the vector.
Instead of this:
for(pthread_t i : preallocatedThreadsPool) {
Your loop needs to enumerate by reference:
Better:
for(pthread_t &i : preallocatedThreadsPool) {
Send a task that instructs the pool thread to requeue the task and then terminate. The poison-task will then run through all the threads in the pool, killing them all off. I have used a null as the poison, (ie, an illegal task) - it does not need to be destructed when it has killed the last thread. You may wish to purge the task queue before sending the null/whatever. If you use a null, you only need a null check in the threads, just after dequeing the task.
You need very little extra code, you don't need to know how many threads in the pool and it will work:)
I have class which has a execute() function. Execution of execute()
function only stops when terminate() function is called. I want to test the execute() function.
class Process{
public:
void execute(){ // start execution until terminate() is called.. }
void terminate(){ //stop the processing of execute()... }
}
My unit test case is given below. I am using MSTest.
TEST_METHOD(StartTest)
{
Process p;
bool isRunning = true;
std::thread th([&](){
p.execute();
isRunning = false;
});
th.detach();
std::this_thread::sleep_for(std::chrono::milliseconds(300));
Assert::isTrue(isRunning);
}
If using thread a good practice should I close the thread inside the test case instead of detaching it from main thread?
Also better suggestion is appreciable.
First of all access to isRunning should be synchronized. In your example you can simply use std::atomic<bool> and be done with it.
Disclaimer: it's been a while since I've done any kind of serios multithreading so take this with a grain of salt. Also, I haven't tested to code, other than to check it compiles.
This is where I would start:
auto test()
{
std::condition_variable cv{};
std::mutex m{};
Process p{};
bool isRunning{true};
std::thread th([&] {
p.execute();
{
std::lock_guard<std::mutex> lk{m};
isRunning = false;
}
cv.notify_one();
});
{
std::unique_lock<std::mutex> lk{m};
// expect timeout
Assert::isFalse(cv.wait_for(lk, std::chrono::milliseconds(300),
[&] () { return !isRunning; }));
}
p.terminate();
{
std::unique_lock<std::mutex> lk{m};
// expect condition to change
Assert::isTrue(cv.wait_for(lk, std::chrono::milliseconds(300),
[&] () { return !isRunning; }));
}
th.join();
}
This way you check both for execute to block and for terminate to terminate and you have more flexibility. If the execute unblocks early you don't wait your full timeout and for terminate you have a wiggle to wait for the other thread to finish and you unblock as soon as it does.
If terminate() fails to stop the execution, will th thread continue
his execution after the end of this test case?
If terminate doesn't stop the execution then the 2nd wait_for ends after timeout returning false and the assert kicks in. I don't know what testing framework you use and what the Assert does.
if it returns the execution to test then the test will block on join until the thread finishes
if it throws an exception then the join is not called and at the destructor of th if the thread has still not ended std::terminate will be called. This can be changed with a try catch
if it forces an exit (e.g. calls std::terminate) then... well... your program ends regardless
This is indeed a problem you need to analyze. It all depends on what you want to do if terminate fails to stop execute within your wait interval.
if you are ok with waiting within test, then all you need to do is make sure join is called. As I've said this is solvable with a try catch.
if you want to end the current test but are ok with the thread still going on then you need to detach the thread if terminate failed to end it.
if you want to kill the thread then... that's not possible. You could instead kill the entire app via std::terminate.
The following process function reads data off a queue and processes it. The wait_and_pop function of masterQueue performs a blocking call. Therefore, control does not move ahead until there exists data on the queue that can be read.
class Context
{
void launch()
{
boost::thread thread1(boost::bind(&Context::push,this ) );
boost::thread thread2(boost::bind(&Context::process,this ) );
std::cout<<"Joining Thread1"<<std::endl;
thread1.join();
std::cout<<"Joining Thread2"<<std::endl;
thread2.join();
}
void process()
{
Data data;
while(status)
{
_masterQueue.wait_and_pop(data); //Blocking Call
//Do something with data
}
}
void push()
{
while(status)
{
//Depending on some internal logic, data is generated
_masterQueue.push(data);
}
}
};
status is a boolean(in global scope). This boolean is set to true by default. It is only changed to false when a signal is caught such as SIGINT, SIGSESV etc. In such a case, the while loop is exited and the program can be exited safely.
bool status = true;
void signalHandler(int signum)
{
std::cout<<"SigNum"<<signum;
status = false;
exit(signum);
}
int main()
{
signal(SIGABRT, signalHandler);
signal(SIGINT, signalHandler);
signal(SIGSEGV, signalHandler);
Context context;
context.launch();
}
Since, no new data is pushed by thread2 when a signal is thrown, control in thread1 is stuck at
_masterQueue.wait_and_pop(data);
How do I force this blocking call to be interrupted?
Is it possible to implement this without changing the internal workings of wait_and_pop
Placing a timeout is not an option, since data may arrive on the queue once in a couple of hours or multiple times a second
Do I push a specific type of data on receiving a signal, e.g INT_MAX/INT_MIN, which the process function is coded to recognise and it exits the loop.
Timeout actually is your answer
You break your loop on getting an answer or having an interrupt
You could also spoof things a bit by having the inturrupt push a noop to the queue
You can try to .interrupt() thread when need to finish it.
If .wait_and_pop() uses standard boost mechanism for wait(condition variable or like), it will definitely be interrupted even in blocked state via throwing boost::thread_interrupted exception. If your masterQueue class is reliable wrt exceptions, then such interruption is safe.