The main thread is loading tasks into a queue.
A worker thread is dealing with these tasks.
My code is like this:
//Core subclass a QThread
Core::AddTask()
{ ...
mutex.lock();
tasks.append(task);
mutex.unlock();
start();//which calls the run function
}
Core::RefreshTask()
{ ...
mutex.lock();
tasks.clear();
mutex.unlock();
// Calculate the new tasks...
...
//foreach newly added task call
AddTask();
}
Core::run()
{ ...
while (1)
{
finish = false;
mutex.lock();
tasks.dequeue();
if (tasks.size() == 0)
finish = true;
mutex.unlock();
...
if (finish)
break;
}
}
However I found the worker thread failed to finish all the tasks because when the run function is being processed, it will not response to start() call.
Then in the situation that: the run function is processing the last task and in the sametime AddTask is being called, then its start() call will do nothing. And the run() function finish and ignore the task.
I know a signal/slot mechanism could solve the problem. But I am forced to use the old QThread::run() style multithreading...
Any suggestions how to properly write a producer consumer pattern in Qt?
I think you don't need call start() in Core::AddTask(). When you add new task to task list, you can send some kind of event message. It can be Qt signal, condition variable or something else.
Event loop works in separate thread and process tasks. If task list is empty, event loop waits for an event.
Related
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 use AMQP-CPP lib with libev backend. I try to create a class which will open a connection and do consuming. I want to run connection's loop in a worker thread in order not to block the main thread. That part of code looks like this
...
m_thread.reset(new std:thread([this]()
{
ev_run(m_loop, 0);
}));
...
Then at some point I want to stop the loop. I have read that it is possible to do it with ev_break() function. However, it should be called from the same thread as ev_run() was called. More search showed that ev_async_send() function might do that, but I cannot figure out how.
How can I do it? Any ideas?
Here is an example:
void asyncCallback(EV_P_ ev_async*, int)
{
ev_break(m_loop, EVBREAK_ONE);
}
void MyClass::stopLoop()
{
ev_async_init(&m_asyncWatcher, asyncCallback);
ev_async_start(m_loop, &m_asyncWatcher);
ev_async_send(m_loop, &m_asyncWatcher);
m_thread->join();
}
// in the class async watcher should be defined
ev_async m_asyncWatcher;
By calling stopLoop() function from another thread it stops the loop that started from m_thread worker thread.
I want to have a class method running in a separate thread :
std::thread myThread(&Class::method, this);
myThread.join();
//Other events
While doing this, the other events occur only when the Class:method is over, not simultaneously.
What did I forget ?
You are calling .join() on the thread, which blocks until that thread has finished, to run things concurrently with that thread either call join() after everything else that you want to run concurrently has finished, or call detach() on the thread object instead
For example
auto th = std::thread{[]() { ... }};
do_something();
th.join();
Here in this example do_something() will run concurrently with the thread th, or you can call detach()
std::thread{[]() { ... }}.detach();
do_something();
This is what happens:
Start a thread and have it run &Class::method
std::thread myThread(&Class::method, this);
Wait until the thread has ended.
myThread.join();
Do other things in the curren thread
//Other events
As you can see, your myThread.join() pauses your current thread.
Do it like this instead:
std::thread myThread(&Class::method, this);
//Other events
myThread.join();
Alternatively; don't perform that join and call myThread.detach(); instead.
I have two threads, lets say thread "A" and thread "B".
Thread "A" post's custom QEvent to thread "B", and then it should wait till thread "B" processes this event.
What I did so far:
My event class:
class IPCMessageEvent : public QEvent
{
public:
IPCMessageEvent(QWaitCondition* pConditions) : QEvent(IPC_MESSAGE_RECEIVED)
, mpWaitCondition(pConditions)
{ };
~IPCMessageEvent()
{
mpWaitCondition->wakeOne();
};
private:
QWaitCondition* mpWaitCondition;
};
My thread "A":
QWaitCondition recvCondition;
IPCMessageEvent* pEvent = new IPCMessageEvent(&recvCondition);
QCoreApplication::postEvent(gpApp, pEvent);
QMutex mutex;
mutex.lock();
recvCondition.wait(&mutex, IPC_MESSAGE_WAIT_TIMEOUT);
My thread "B": Processes the received event and destroyes it. ~IPCMessageEvent destructor is called and therefore wakeOne() will be initiated for the recvCondition in thread "A".
Everything seems to work just fine, it's just one thing!
It looks like sometimes ~IPCMessageEvent is called sooner then expected...
QCoreApplication::postEvent(gpApp, pEvent);
<---- pEvent is already destroyed here ---->
QMutex mutex;
mutex.lock();
So my recvCondition.wait(&mutex, IPC_MESSAGE_WAIT_TIMEOUT); will be locked and will reach the timeout.
Are there any other ways of doing this kind of synchronization?
Or maybe someone have any suggestions how to fix/overcome this problem?
Well, you have a classical race condition. Your thread A may is interrupted directly after posting the event and thread B then processes and destroys it. Since notifications of condition variables have only an effect if somebody is already waiting, you miss the notification and thus your block infinitely.
So you need to lock the mutex before posting the event. However, this requires that your thread B also needs to lock this mutex when processing the event. Otherwise, you cannot prevent the race condition as thread B has no reason to wait for anything (or to know that it should "wait" until thread A is ready waiting on the condition variable).
Alternative:
If you use a signal/slot connection between the two threads (or the objects living in the two threads), you can use a Qt::BlockingQueuedConnection. This ensures that thread A blocks after emitting the signal until the event loop in thread B processed it.
Thanks Johannes,
I would really need to try and use your suggested alternative with signals/slots.
What I did for now is:
I've created a QMutex and boolean flag that are used between thread "A" and thread "B".
bool mIsProcessingMessage;
QMutex mIsProcessingMessageLock;
In thread "A" I'm posting my event like this:
IPCMessageEvent* pEvent = new IPCMessageEvent();
{ // Inform everyone that we will be processing our message.
QMutexLocker locker(&mIsProcessingMessageLock);
mIsProcessingMessage = true;
};
QCoreApplication::postEvent(gpApp, pEvent, Qt::HighEventPriority);
forever // Loop until event will get processed.
{
QMutexLocker locker(&mIsProcessingMessageLock);
if (mIsProcessingMessage == false)
break;
::Sleep(2); // Don't load up the CPU.
};
In thread "B" when my event is processed I just set my "mIsProcessingMessage" flag to true like this:
{
QMutexLocker locker(&mIsProcessingMessageLock);
mIsProcessingMessage = false;
};
Maybe it's not the best solution, but it works for now ;)
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
}
}
}