I've created my own TestService which runs on a separate QThread, but when the MainLoop terminates the QThread::finished signal does not get emitted. I saw a similar question, but the problem was slightly different there because the OP was overloading QThread whereas I simply move my class to the thread.
Note that I do not overload the QThread class, I only overload QObject based on this example: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
Here is my TestService class:
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <iostream>
using namespace std;
class TestService: public QObject
{
Q_OBJECT;
private:
volatile int _count;
QWaitCondition _monitor;
QMutex _mutex;
QThread* _thread;
public:
TestService(int numSeconds)
{
_count = numSeconds;
_thread = NULL;
cout << "TestService()" << endl;
}
virtual ~TestService()
{
cout << "~TestService()" << endl;
}
void Start()
{
QMutexLocker locker(&_mutex);
if(_thread == NULL)
{
_thread = new QThread;
// Move this service to a new thread
this->moveToThread(_thread);
// The main loop will be executed when the thread
// signals that it has started.
connect(_thread, SIGNAL(started()), this, SLOT(MainLoop()));
// Make sure that we notify ourselves when the thread
// is finished in order to correctly clean-up the thread.
connect(_thread, SIGNAL(finished()), this, SLOT(OnFinished()));
// The thread will quit when the sercives
// signals that it's finished.
connect(this, SIGNAL(Finished()), _thread, SLOT(quit()));
// The thread will be scheduled for deletion when the
// service signals that it's finished
connect(this, SIGNAL(Finished()), _thread, SLOT(deleteLater()));
// Start the thread
_thread->start();
}
}
void Stop()
{
_count = 0;
_monitor.wakeAll();
}
private slots:
void MainLoop()
{
cout << "MainLoop() Entered" << endl;
while(_count > 0)
{
cout << "T minus " << _count << " seconds." << endl;
QMutexLocker locker(&_mutex);
_monitor.wait(&_mutex, 1000);
_count--;
}
cout << "MainLoop() Finished" << endl;
emit Finished();
}
virtual void OnFinished()
{
cout << "OnFinished()" << endl;
}
signals:
void Finished();
};
Here is the testing code:
void ServiceTest()
{
cout << "Press q to quit." << endl;
cout << "Press s to start." << endl;
cout << "Press t to stop." << endl;
QSharedPointer<TestService> testService(new TestService(10));
char in = 'a';
while( in != 'q' )
{
switch(tolower(in))
{
case 's':
testService->Start();
break;
case 't':
testService->Stop();
break;
default:
break;
}
cin.get(in);
in = tolower(in);
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ServiceTest();
QTimer::singleShot(0, &a, SLOT(quit()));
return a.exec();
}
The output is:
Press q to quit.
Press s to start.
Press t to stop.
TestService()
s
MainLoop() Entered
T minus 10 seconds.
T minus 9 seconds.
T minus 8 seconds.
t
MainLoop() Finished
q
~TestService()
Press any key to continue . . .
Could anybody explain why is finished not being emitted how I can fix it?
Signal finished() gets emitted of cause, but you don't catch it.
Here:
connect(_thread, SIGNAL(finished()), this, SLOT(OnFinished()));
Qt::QueuedConnection is used, as _thread and this (service) are in different threads.
By the time finished() is emitted, _thread's event loop already finished executing, so signal will not be delivered to the slot.
You can explicitly use Qt::DirectConnection.
EDIT:
QTherad works like this:
QThread::start()
{
emit started();
run();
emit finished();
}
QThread::run()
{
eventloop->exec();
}
So, by the time finished is emitted, eventloop already stop execution. And as you move service to _thread, service's event loop is _thread event loop.
Note, that QObject itself has no its own event loop. Event loops are created by dialogs, threads and application.
Actually I will recommend in your simple case just use QtConcurent::run, as you do not perform actual event processing in the new thread, but just run single function.
Related
So i have 2 classes, one named ConsoleInput, which contains member function check4Flood and second named AntiFloodSys, in which connect function for signal-slot system is present, and also its signal (QTimer) and slot.
AntiFloodSys object is in check4Flood member function which scope never ends as inside there is infinite while loop. Thus the object is never destroyed. So when the object anti is created, the constuctor of AntiFloodSys class is called and therefore the connection between signal and slot.
My question at which point of the code the connection timeout signal and mySlot is separated, so the slot is never fired?
ConsoleInput cpp file looks like this:
void ConsoleInput::check4Flood(int& lineCounter)
{
AntiFloodSys anti;
while(1)
{
std::string chatLine[2];
std::cin >> chatLine[0] >> chatLine[1];
anti.input(chatLine[0], chatLine[1]);
}
}
and AntiFloodSys class like this:
AntiFloodSys::AntiFloodSys(QObject *parent) : QObject(parent)
{
timeFrame = 1000 ;
timer = new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(mySlot()));
timer->start(timeFrame);
std::cout << "AntiFloodSys constructor - timer starts " << "\n";
}
AntiFloodSys::~AntiFloodSys()
{
std::cout << "AntiFloodSys Destructor" << "\n";
}
void AntiFloodSys::input(std::string nick_, std::string line_)
{
nick = nick_;
line = line_;
std::cout << "nick: " << nick << " line: " << line << " " << "\n";
}
void AntiFloodSys::mySlot()
{
std::cout << "slot" << "\n";
}
The problem is your while(1): the Qt event loop is never processed because your program is blocked in this loop.
You can force the event loop processing calling QCoreApplication::processEvents() but the std::cin is a blocking function. So, it will not completly solve your problem.
You should move your loop in a dedicated thread that will send data to the main thread (e.g. signals/slots system).
You can also use the QSocketNotifier class to create a non blocking stdin access.
A quick example:
class Widget: public QWidget
{
Q_OBJECT
public:
Widget(): QWidget(), input(new QLabel("Edit", this))
{
connect(this, &Widget::displayText, input, &QLabel::setText);
}
private:
QLabel* input;
signals:
void displayText(QString const&);
};
class UserInput: public QObject
{
Q_OBJECT
public:
UserInput(): QObject()
{}
public slots:
void run()
{
while(1) // User Input in an infinite loop
{
std::string line;
std::cin >> line;
emit inputReceived(QString::fromStdString(line));
}
}
signals:
void inputReceived(QString const&);
};
int main(int argc, char** argv) {
QApplication app(argc, argv);
Widget* w = new Widget();
UserInput* input = new UserInput();
QThread* thread = new QThread();
input->moveToThread(thread); // Move the user input in another thread
QObject::connect(thread, &QThread::started, input, &UserInput::run);
QObject::connect(input, &UserInput::inputReceived, w, &Widget::displayText);
thread->start();
w->show();
return app.exec();
}
I have and application with a worker thread. When I try to stop the thread and close my application it crashes.
I am creating the worker and the thread and connecting the signals and slots as:
QPointer<QThread> monitorThread(new QThread());
QPointer<ItemMonitor> monitor(new ItemMonitor(items));
monitor->moveToThread(monitorThread);
//closeInitiated signal emitted when custom close button is clicked
connect(this, SIGNAL(closeInitiated()), monitor, SLOT(finishUp()));
connect(monitor, SIGNAL(finished()), monitorThread, SLOT(quit()));
connect(monitor, SIGNAL(finished()), monitor, SLOT(deleteLater()));
connect(monitor, SIGNAL(finished()), this, SLOT(closeApplication()));
connect(monitorThread, SIGNAL(started()), monitor, SLOT(beginMonitoring()));
connect(monitorThread, SIGNAL(finished()), monitorThread, SLOT(deleteLater()));
//start monitoring
monitorThread->start();
The ItemMonitor class which is running in the QThread is
#include "itemmonitor.h"
#include "todoitem.h"
#include <QObject>
#include <iostream>
#include <QTimer>
ItemMonitor::ItemMonitor(std::vector< QPointer<ToDoItem> >& items_)
:items(items_),
shouldRun(true){
std::cout << "Monitor created" << std::endl;
}
void ItemMonitor::beginMonitoring(){
if(shouldRun){
for(int i=0; i<items.size(); i++){
items[i]->setSecsTillDeadline();
}
QTimer::singleShot(100, this, SLOT(beginMonitoring()));
}else{
emit finished();
}
}
void ItemMonitor::finishUp(){
shouldRun = false;
}
and the closeApplication function in my main class is:
void ToDoList::closeApplication(){
while(monitorThread->isRunning()){
std:: cout << "thread not closed" << std::endl;
}
QApplication::quit();
}
what is odd to me is that if I make no attempt to quit the thread and just try to close the applicationt then there are no errors
connect(monitor, SIGNAL(finished()), monitorThread, SLOT(quit()));
connect(monitorThread, SIGNAL(finished()), monitorThread, SLOT(deleteLater()));
monitor emit finished() -> monitorThread->quit() -> monitorThread emit finished() -> monitorThread->deleteLater()
after the monitors emit finished() signal, the monitorThread will be deleted.
void ToDoList::closeApplication(){
while(monitorThread->isRunning()){//maybe you should check the monitorThread for null
std:: cout << "thread not closed" << std::endl;
}
QApplication::quit();
}
This example is for testing QThread. The main objective is to be able to run one time consuming blocking method in a dedicated thread and
being able to terminate and restart the thread at any point. The blocking method is a 3rd party lib which is outside our control. I know the documentation of Qt discourages using QThread::terminate but at the moment I do not see any other way.
Below is a pseduo example of the code needed to run in a dedicated thread. There is basically one method which can take 10-15 minutes to process. There is no logical place to add moveToThread to take the affinity back to main thread on QThread::termination, or executiong processEvent to handle a QThread::quit() method.
void run()
{
// initiate variables
thirdparty lib(var1, var2);
int res = lib.execute(var3, var4, var6);
// handle result and exit
}
Using Qt 4.7 on Windows 7.
Running the code produces this output
Test::doWork thread: QThread(0x219e960)
Test::started thread: QThread(0x239bce8)
Test::doTerminate thread: QThread(0x239bce8)
Test::doWork thread: QThread(0x239bce8)
QObject::moveToThread: Current thread (0x219e960) is not the object's thread (0x239bce8). Cannot move to target thread (0x239bd20)
The moveToThread API fails on the second execution of the Test::doWork() method. This appears to be because the Test instance has affinity to another thread (which is terminated at this point). How can I then change the affinity?
What is the recommended way to terminate and restart a QThread? Do I need to delete the Test instance?
The code;
#include <QCoreApplication>
#include <QThread>
#include <iostream>
#include <QDebug>
#include "Worker.h"
#include "Windows.h"
class Test : public QObject
{
Q_OBJECT
QThread* m_thread;
int m_state;
public:
Test() : m_thread(0), m_state(3) { }
public slots:
void doWork()
{
qDebug() << "Test::doWork thread:" << QObject::thread();
if (!m_thread)
{
m_thread = new QThread();
QObject::moveToThread(m_thread);
QObject::connect(m_thread, SIGNAL(started()), this, SLOT(started()));
QObject::connect(m_thread, SIGNAL(finished()), this, SLOT(finished()));
QObject::connect(m_thread, SIGNAL(terminated()), this, SLOT(terminated()));
m_thread->start();
}
}
void started()
{
qDebug() << "Test::started thread:" << QObject::thread();
Sleep(60);
}
void finished()
{
qDebug() << "Test::finished thread:" << QObject::thread();
}
void terminated()
{
qDebug() << "Test::terminated thread:" << QObject::thread();
}
void doTerminate()
{
qDebug() << "Test::doTerminate thread:" << QObject::thread();
QObject::disconnect(m_thread);
m_thread->terminate();
m_thread->wait();
m_thread = NULL;
}
int state()
{
return m_state;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
test.doWork();
Sleep(10);
test.doTerminate();
Sleep(10);
test.doWork();
return a.exec();
}
Instead of using terminate, you can call the more acceptable function quit().
While trying to make a multi-camera system work with a different thread handling a different camera, I couldn't get signals and slots working correctly between different threads. I knew something was wrong with the fact that the object sending the signal and the related slot's object were living in different threads, and thus I knew that I probably only had to find an appropriate "connection type" parameter for the connection. Eventually, I ended up discovering that only using Qt::DirectConnection would make everything work as it should.
Find the simplified code below. Here's a small description of how everything should work.
Application is the main program which is supposed to create all the threads and start them. In this simplified version, it then simply waits for the worker to finish its jobs through the slot "quit".
Worker is the object which performs one of the threaded tasks. In this simplified example, I just wait some time before finishing the computation. The worker then emits a signal which is directed to the application instance, which is then allowed to wait for all the threads and quit QCoreApplication.
What I am finding is that if I don't use Qt::DirectConnection in the second connect, then the finished() signal of the worker does not trigger the quit() slot of the thread, which means that the application then remains hanging waiting for the thread.
My question is: why is that so? since the two objects (the worker and the thread) belong to different threads, shouldn't I be using QueuedConnection, or something else? I thought DirectConnection should only be used for objects belonging to the same thread.
main.cpp:
#include <iostream>
#include <QCoreApplication>
#include "program.h"
using namespace std;
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
Program *p = new Program;
p->execute();
app.exec();
delete p;
}
program.h
#ifndef _PROGRAM_H_
#define _PROGRAM_H_
#include <QThread>
#include <QTimer>
#include "worker.h"
class Program: public QObject {
Q_OBJECT
private:
Worker *worker;
QThread *thread;
public:
void execute();
public slots:
void quit();
};
#endif // _PROGRAM_H_
program.cpp
#include "worker.h"
using namespace std;
void Program::execute() {
worker = new Worker();
thread = new QThread;
worker->moveToThread(thread);
cout << "Connection established: "
<< connect(thread, SIGNAL(started()), worker, SLOT(process()))
<< endl;
// slot not called if I remove the fifth parameter
// or if I put Qt::QueuedConnection
cout << "Connection established: "
<< connect(worker, SIGNAL(finished()), thread, SLOT(quit()),
Qt::DirectConnection)
<< endl;
cout << "Connection established: "
<< connect(worker, SIGNAL(finished()), this, SLOT(quit()))
<< endl;
cout << "Connection established: "
<< connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()))
<< endl;
cout << "Connection established: "
<< connect(worker, SIGNAL(finished()), thread, SLOT(deleteLater()))
<< endl;
thread->start();
}
void Program::quit() {
cout << "waiting.." << endl;
thread->wait();
cout << " .. I'm done!" << endl;
cout << "quitting from all.." << endl;
QCoreApplication::quit();
cout << " .. I'm done!" << endl;
}
#include "program_moc.cpp"
worker.h
#ifndef _WORKER_H_
#define _WORKER_H_
#include <QObject>
class Worker: public QObject {
Q_OBJECT
public slots:
void process();
signals:
void finished();
};
#endif // _WORKER_H_
worker.cpp:
#include <iostream>
#include <unistd.h>
#include "worker.h"
using namespace std;
void Worker::process() {
cout << "Worker::process() started" << endl;
usleep(1000000);
cout << "Worker::finished() being emitted" << endl;
emit finished();
cout << "Worker::process() finished" << endl;
}
#include "worker_moc.cpp"
EDIT
Following #ariwez 's answer does solve the problem in this specific simplified example, but it doesn't in a slightly more complex one, which I am adding now.
In this example,
Program has its own job to execute periodically through the use of a QTimer. Program also has yet another QTimer which is used to simulate the user quitting the program, which triggers the execution of the slot Program::quit().
Worker executes its own job until his quitting flag gets set to false. This is done inside Program::quit().
As in the previous example, worker successfully finishes its procedure and emits the finished() signal, which is also supposed to be connected with the thread's quit() slot. However, somehow the slot must not be executed, because Program hangs waiting for the thread. Differently from the previous example, relocating the moveToThread procedure does not solve the issue: everything works if and only if I use the Qt::DirectConnection type for the connection between Worker::finished() and QThread::quit(), and I can't understand why.
main.cpp: same as above
program.h:
#ifndef _PROGRAM_H_
#define _PROGRAM_H_
#include <QThread>
#include <QTimer>
#include "worker.h"
class Program: public QObject {
Q_OBJECT
private:
QTimer *timer, *quittingTimer;
Worker *worker;
QThread *thread;
public:
~Program();
void execute();
private slots:
void quit();
void update();
};
#endif // _PROGRAM_H_
program.cpp:
#include <iostream>
#include <QCoreApplication>
#include "program.h"
#include "worker.h"
using namespace std;
Program::~Program() {
delete timer;
delete quittingTimer;
}
void Program::execute() {
timer = new QTimer();
timer->setInterval(500);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
worker = new Worker;
thread = new QThread;
cout << "Connection established: "
<< connect(thread, SIGNAL(started()), worker, SLOT(process()))
<< endl;
// doesn't work if I remove Qt::DirectConnection
cout << "Connection established: "
<< connect(worker, SIGNAL(finished()), thread, SLOT(quit()),
Qt::DirectConnection)
<< endl;
cout << "Connection established: "
<< connect(worker, SIGNAL(finished()), this, SLOT(quit()))
<< endl;
cout << "Connection established: "
<< connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()))
<< endl;
cout << "Connection established: "
<< connect(worker, SIGNAL(finished()), thread, SLOT(deleteLater()))
<< endl;
worker->moveToThread(thread);
timer->start();
thread->start();
// simulates user pressing key to close program
quittingTimer = new QTimer();
quittingTimer->singleShot(4000, this, SLOT(quit()));
}
void Program::quit() {
cout << "timer->stop()" << endl;
timer->stop();
cout << "worker->quit()" << endl;
worker->quit();
cout << "thread->wait()" << endl;
thread->wait();
cout << "qcore->quit()" << endl;
QCoreApplication::quit();
}
void Program::update() {
cout << "Program::update() called" << endl;
}
#include "program_moc.cpp"
worker.h:
#ifndef _WORKER_H_
#define _WORKER_H_
#include <QObject>
class Worker: public QObject {
Q_OBJECT
private:
bool quit_flag;
public:
void quit();
public slots:
void process();
signals:
void finished();
};
#endif // _WORKER_H_
worker.cpp:
#include <iostream>
#include <unistd.h>
#include <QThread>
#include "worker.h"
using namespace std;
void Worker::quit() {
quit_flag = true;
}
void Worker::process() {
quit_flag = false;
while(!quit_flag) {
cout << "Worker::process() is processing" << endl;
usleep(300000);
}
cout << "Worker::finished() is being sent" << endl;
emit finished();
cout << "Worker::finished() is sent" << endl;
}
#include "worker_moc.cpp"
EDIT 2
Re-reading the article in #ariwez 's link I found out which was the problem in this second example. The problem was that the main event loop was being interrupted, while waiting for the thread's QThread::finished() signal, and so the Worker::finished() signal could not be dispatched into the QThread::quit() slot. So yeah, basically I deadlocked myself.
You moveToThread before connects that's why everything is in one thread.
I think I see what the issue might be.
Your directConnection, which is really bad thing to do accross theads as it acts like an interrupt - executs immediatley. But it is BECAUSE it executes immediatley that it works in your case. When the thread closes down it emits the quit() signal.... then usually it "quits" but in direcetConnection it immediatley executes the slot finished() and then quits.
If you have a QueuedConnection then it would emit the signal to the queue and then finish "quitting". However once the thread is stopped the thread queue is never servied so your finished() function is never run.
Perhaps a better way to do this would be to connect to your object finished() send your signal there and then get the object within the thread to stop the thread itsself. (i.e. don't stop the thread remotly, stop the object, which in turn stops its thread).
How can I wake up a QThread when it is sleeping?
I have a thread that is running in the background and now and then wakes up and does some small stuff, however if I would like to stop that thread in a controlled manner I have to wait for him to wake up by him self in order to make him quit. And since he is sleeping quite long this can be quite annoying.
Here is a little example code that show the basic problem.
Let's start with the thread that in this example sleeps for 5 seconds and then just prints a dot.
#include <QDebug>
#include "TestThread.h"
void TestThread::run()
{
running = true;
while(running == true)
{
qDebug() << ".";
QThread::sleep(5);
}
qDebug() << "Exit";
}
void TestThread::stop()
{
running = false;
}
Then we have the main that starts the thread and then kills him.
#include <QDebug>
#include "TestThread.h"
int main(int argc, char *argv[])
{
qDebug() << "Start test:";
TestThread *tt = new TestThread();
tt->start();
sleep(2);
tt->stop();
tt->wait();
delete tt;
}
The problem is that the tt->wait(); must wait the 5s that the thread is sleeping.
Can I just call something like a "wakeup from sleep" so he can continue.
Or is there a better way to do this?
/Thanks
Update I got it working with a QMutex and the tryLock:
#include <QDebug>
#include "TestThread.h"
QMutex sleepMutex;
void TestThread::run()
{
qDebug() << "Begin";
//1. Start to lock
sleepMutex.lock();
//2. Then since it is locked, we can't lock it again
// so we timeout now and then.
while( !sleepMutex.tryLock(5000) )
{
qDebug() << ".";
}
//4. And then we cleanup and unlock the lock from tryLock.
sleepMutex.unlock();
qDebug() << "Exit";
}
void TestThread::stop()
{
//3. Then we unlock and allow the tryLock
// to lock it and doing so return true to the while
// so it stops.
sleepMutex.unlock();
}
But would it be better to use the QWaitCondition? Or is it the same?
Update: The QMutex breaks if it is not the same tread that starts and stop him,
so here is a try with QWaitCondition.
#include <QDebug>
#include <QWaitCondition>
#include "TestThread.h"
QMutex sleepMutex;
void TestThread::run()
{
qDebug() << "Begin";
running = true;
sleepMutex.lock();
while( !waitcondition.wait(&sleepMutex, 5000) && running == true )
{
qDebug() << ".";
}
qDebug() << "Exit";
}
void TestThread::stop()
{
running = false;
waitcondition.wakeAll();
}
You could use a QWaitCondition rather than a simple sleep. If gives you much more control.
Example usage here: Wait Conditions Example
I don't think that a portable solution exists (though there might be some facilities in some operation systems, like POSIX signals). Anyway, Qt itself doesn't provide such means, thus you could simulate it like
void TestThread::run()
{
running = true;
while(running == true)
{
qDebug() << ".";
// Quantize the sleep:
for (int i = 0; i < 5 && running; ++i) QThread::sleep(1);
}
qDebug() << "Exit";
}
But the best solution would still be a QWaitCondition, as pointed out by Mat.