in my program, I am subclassing QThread, and I implemented the virtual method run() like so:
void ManagerThread::run() {
// do a bunch of stuff,
// create some objects that should be handled by this thread
// connect a few signals/slots on the objects using QueuedConnection
this->exec(); // start event loop
}
Now, in another thread (let's call it MainThread), I start the ManagerThread and wait for its started() signal, after which I proceed to use the signals and slots that should be handled by ManagerThread. However, the started() signal is essentially emmitted right before run() is called, so depending on thread scheduling I lose some signals from MainThread, because the event loop hasn't started yet!
(EDIT: turns out that's not the problem, it's just the signals are not connected in time, but for the same reason)
I could emit a signal right before calling exec(), but that's also asking for trouble.
Is there any definitive/simple way of knowing that the event loop has started?
Thanks!
EDIT2:(SOLUTION)
Alright, so it turns out the problem isn't exactly what I phrased. The fact that the event loop hasn't started isn't the problem, since signals should get queued up until it does start. The problem is, some of the signals would not get connected in time to be called- since the started() signal is emitted before run() is called.
The solution is to emit another custom signal after all the connections and right before exec. That way all signals/slots are ensured to be connected.
This is the solution to my problem, but not really an answer to the thread title. I have accepted the answer that does answer the title.
I have left all my code below for those curious, with the solution being, to wait for another signal in the instance() method.
CODE:
Many of you are saying that I cannot lose signals, so here is my whole class implementation. I will simplify it to just the bare necessities.
Here is the interface to ManagerThread:
// singleton class
class ManagerThread: public QThread {
Q_OBJECT
// trivial private constructor/destructor
public:
static ManagerThread* instance();
// called from another thread
public:
void doSomething(QString const& text);
// emitted by doSomething,
// connected to JobHandler whose affinity is this thread.
signals:
void requestSomething(QString const& text);
// reimplemented virtual functions of QThread
public:
void run();
private:
static QMutex s_creationMutex;
static ManagerThread* s_instance;
JobHandler* m_handler; // actually handles the requests
};
Some relevant implementations. Creating the singleton instance of the thread:
ManagerThread* ManagerThread::instance() {
QMutexLocker locker(&s_creationMutex);
if (!s_instance) {
// start socket manager thread, and wait for it to finish starting
s_instance = new ManagerThread();
// SignalWaiter essentially does what is outlined here:
// http://stackoverflow.com/questions/3052192/waiting-for-a-signal
SignalWaiter waiter(s_instance, SIGNAL(started()));
s_instance->start(QThread::LowPriority);
qDebug() << "Waiting for ManagerThread to start";
waiter.wait();
qDebug() << "Finished waiting for ManagerThread thread to start.";
}
return s_instance;
}
Reimplementation of run that sets up signals/slots and starts event loop:
void ManagerThread::run() {
// we are now in the ManagerThread thread, so create the handler
m_handler = new JobHandler();
// connect signals/slots
QObject::connect(this,
SIGNAL(requestSomething(QString const&)),
m_handler,
SLOT(handleSomething(QString const&)),
Qt::QueuedConnection);
qDebug() << "Starting Event Loop in ManagerThread";
// SOLUTION: Emit signal here and wait for this one instead of started()
this->exec(); // start event loop
}
Function that delegates the handling to the correct thread. This is where
I emit the signal that is lost:
void ManagerThread::doSomething(QString const& text) {
qDebug() << "ManagerThread attempting to do something";
// if calling from another thread, have to emit signal
if (QThread::currentThread() != this) {
// I put this sleep here to demonstrate the problem
// If it is removed there is a large chance the event loop
// will not start up in time to handle the subsequent signal
QThread::msleep(2000);
emit(requestSomething(text));
} else {
// just call directly if we are already in the correct thread
m_handler->handleSomething(text);
}
}
Finally, here is the code from MainThread that will fail if the event loop doesn't start in time:
ManagerThread::instance()->doSomething("BLAM!");
Assuming that the handler just prints out its text, here is what gets printed out on a successful run:
Waiting for ManagerThread to start
Finished waiting for ManagerThread thread to start.
Starting Event Loop in ManagerThread
ManagerThread attempting to do something
BLAM!
And here is what happens on an unsuccessful run:
Waiting for ManagerThread to start
Finished waiting for ManagerThread thread to start.
ManagerThread attempting to do something
Starting Event Loop in ManagerThread
Clearly the event loop started after the signal was emitted, and BLAM never prints.
There is a race condition here, that requires the knowledge of when the event loop starts,
in order to fix it.
Maybe I'm missing something, and the problem is something different...
Thanks so much if you actually read all that! Phew!
If you setup the connections right, you shouldn't be losing the signals. But if you really want to get a notice on the start of the thread's event loop, you can try QTimer::singleShot() in your run() right before calling exec(). It will be delivered when the event loop starts and only delivered once.
You could look at QSemaphore to signal between threads. Slots and signals are better for ui events and callbacks on the same thread.
Edit: Alternately you could combine QMutex with QWaitCondition if a semaphore is not applicable. More example code to see how you are using the ManagerThread in conjunction with the MainThread would be helpful.
This is a non-issue. Signals between threads are queued (more specifically, you need to set them up to be queued in the connect() call because direct connections between threads aren't safe).
http://doc.qt.io/qt-5/threads-qobject.html#signals-and-slots-across-threads
You could create the signal/slots connections in the constructor of the ManagerThread. In that way, they are certainly connected even before run() is called.
Related
Qt doc:
If no event loop is running, events won't be delivered to the object.
For example, if you create a QTimer object in a thread but never call
exec(), the QTimer will never emit its timeout() signal. Calling
deleteLater() won't work either. (These restrictions apply to the main
thread as well.)
Does this mean that signal void QTimer::timeout() will also issue a QEvent?
If so, where does the Qt doc state this?
where does the Qt doc state this?
Nowhere, because it shouldn't matter to the user of QTimer. The timer event is an implementation detail. It is delivered to the timer object itself, so you'd really have to go out of your way to intercept it. Here's how QTimer works:
class QTimer : public QObject {
Q_TIMER
QBasicTimer m_timer;
protected:
void timerEvent(QTimerEvent * ev) override {
if (ev->timerId() == m_timer.timerId())
emit timeout();
}
/*...*/
};
If you think about it, there's no way of emitting any signals without running the code that emits the signals, and the only way to safely run such code that emits things asynchronously is to code for run-to-completion chunks that cede control to the event loop at every opportunity. The event loop is notified by the platform that a timer has timed out, and emits a signal right then. You'd be in deep trouble if Qt issued signals such as timer timeouts from intrusive asynchronous callbacks like Unix signals: just read about how few things you can do while in a signal handler - it'd be no different than an interrupt handler.
I'm writing an application with a button to start/stop a worker thread (which implements QThread).
The worker thread keeps scheduling a job every few milliseconds.
To terminate the worker thread, I'm calling worker.quit() (worker.exit(0) doesn't work either) method from the GUI thread and waiting the finished signal to be fired.
The problem is that even though the finished signal is fired, the thread isn't terminated.
Here is a minimal example:
https://gist.github.com/NawfelBgh/941babdc011f07aa4ab61570d7b88f08
Edit
My interpretation of what happened was wrong: The worker thread was being terminated but the method iter was getting executed in the main thread as said by #sergey-tachenov and as confirmed from the logging generated with the code:
void run() {
std::cout <<"From worker thread: "<<QThread::currentThreadId() << std::endl;
...
void iter() {
std::cout <<"From thread: "<<QThread::currentThreadId() << std::endl;
...
void MainWindow::on_pushButton_clicked()
{
std::cout <<"From main thread: "<<QThread::currentThreadId() << std::endl;
I switched to a different design which doesn't rely on QTimers. But I didn't submit it as an answer since the title of this question is "How to quit the event loop of a worker QThread".
The thread is terminated. Only your timer runs not in the thread you've started but in the main thread, that's why it isn't stopped. This is because it uses queued connections by default and the thread object lives in the thread in which it was created which is the main thread. To fix it:
Do not subclass QThread. It's usually a bad idea unless you want to actually extend QThread's functionality.
Create a separate worker object that inherits QObject.
Use moveToThread to move the worker object to the created thread. It will cause all its slots to fire actually in the thread. If you use default or queued connections, that is.
The QThread docs provide an excellent example on that (the first one).
Note that if you actually want to use data provided by the thread to update GUI, you'll have to somehow correctly publish that data to the GUI thread (possibly using emit and queued connections) instead of trying to update GUI directly from the thread. And if you want to access shared data, you probably need to guard it with a QMutex, not like you do with your shared counter.
I am wondering how to tell a QObject to process all signals and call the slots associated with them. Here's the concrete problem I am having, for a better description of the question:
My program consists of three Qthreads : Main, Communication and Input.
The communication thread handles communication via the network, the Input thread handles user input, and both have several signal-slot connections to the main thread. Whenever a network event occurs, or whenever the user inputs a commandline command, a signal from the respective thread is called, which then activates the appropriate connected slot in the main thread. The main thread's role is to process these events. My code looks as follows:
QApplication a(argc, argv);
CommObj co; //inherits from QThread
co.start(); //Starts the thread
InputObj io; //inherits from QThread
io.start(); //Starts the thread
MainObj u(&co,&io);
return a.exec();
Now, what I want to achieve is for the main thread to not reach the last line.
My intentions are to call a method run() within the constructor of MainObj which is going to do something along the lines of this:
void run ()
{
forever
{
//process all signals..
}
}
However, I do not know how to implement the process all signals part. Any advice on how this could be done (including workarounds) would be very welcome.
This is completely unnecessary. a.exec() runs an event loop that will receive and process the events sent by other threads.
When a slot is invoked due to a signal being emitted in a different thread, Qt is posting a QMetaCallEvent to the receiver object. The QObject::event method is able to re-synthesize the slot call based on the data in the event.
Thus, you need to do nothing. a.exec() does what you want. Feel free to invoke it from MainObj's constructor, as qApp->exec() or as QEventLoop loop; loop.exec(), but that's rather bad design.
The real questions are:
Why do you need MainObj's constructor to spin an event loop?
What sort of "user input" are you processing in the io? You can't access any GUI objects from that thread.
Why are you deriving from QThread if you're using Qt's networking? You definitely don't want to do that - it won't work unless you spin an event loop, so you might as well just use a QThread without changes. Well, to be safe, you need just to make the thread destructible, so:
class Thread {
using QThread::run; // make it final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { requestInterruption(); quit(); wait(); }
};
Anyway, by not using standard QThread that spins an event loop, the communication will be one way. Nothing in such threads will be able to react to signals from other threads.
You need to rearchitect as follows:
Use the Thread class as above. It's safe to be destructed at any time.
Have worker objects that run asynchronously using signals/slots/timers.
Move constructed workers to their threads.
What you need is the processEvents function. For example, if you don't want the user to be able to interact with widgets, but you want the graphics to update, use
processEvents(QEventLoop::ExcludeUserInputEvents);
See the documentation for details.
I have an Qt5 c++ app with 2 threads, thread A is started when the main program starts up. The start method of thread A runs successfully.
So far so good. Next, in the main program I send a signal to Thread A to start a QTimer, which it does - but that timer never expires!
Thread B handles tcp connections. When I initiate a telnet connection to my app, thread B fires up and suddenly I see my Qtimer from thread A expiring at normal intervals.
Why is the QTimer from thread A not expiring until thread B starts?
I suspect my threads are getting messed up. note the last section of code below products this:
thread of this: QThread(0x200fe00)
thread of timer: QThread(0x1fff470)
Which suggest my worker object (this), is in a different thread from my timer object. This timer thread address is actually the MAIN thread. Why? I'm confused.
Suggestions?
In my main app I create and start my thread like this:
QThread * MyControllerThread = new QThread(this);
if (MyControllerThread) {
TheController *worker = new TheController(MyControllerThread);
if (worker) {
connect(MyControllerThread, SIGNAL(started()), worker, SLOT(start()));
connect(MyControllerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(MyControllerThread, SIGNAL(finished()), MyControllerThread, SLOT(deleteLater()));
worker->moveToThread(MyControllerThread);
MyControllerThread->start();
}
and in my main app I emit a signal to the new thread:
emit sig_startlocalpeer(Types::EActionLocalServiceStart); // Move the local peer to standby mode to start remote tests
which runs a slot in my thread (TheController object):
connect(&m_remotetestintervaltimer,SIGNAL(timeout()),this,SLOT(expiredRemoteTestIntervalTimer()));
m_remotetestintervaltimer.setTimerType(Qt::VeryCoarseTimer);
m_remotetestintervaltimer.start(REMOTETEST_TIMER_INTERVAL); // Wait between ticks
qDebug() << "thread of this: " << this->thread();
qDebug() << "thread of timer: " << m_remotetestintervaltimer.thread();
Well, it's not a Qt5 bug, it's more an inaccurate understanding of Qt's thread spirit.
In Qt, you have two ways to implement a thread which are using or not an even loop. Here is just a small visual example.
No event loop
myMethodCalledInANewThread
{
do{ ... }while(...);
}
With an event loop
myMethodCalledInANewThread
{
[...]
exec();
}
(Of course you can mix a do/while with an even loop but stay simple).
In QTimer's doc, you can read:
In multithreaded applications, you can use QTimer in any thread that
has an event loop. [...] Qt uses the timer's thread affinity to
determine which thread will emit the timeout() signal. Because of
this, you must start and stop the timer in its thread; it is not
possible to start a timer from another thread.
So I'm pretty sure you don't have a second event loop in your second thread and that's why you have the behaviour you described.
To give you some tips to be totally clear with thread using Qt, I suggest you to read:
QThread doc: https://doc.qt.io/qt-5/qthread.html
QTimer doc: https://doc.qt.io/qt-5/qtimer.html
and a very good article about how QThread implementation is misunderstood by a lot of users:
You're doing it wrong: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
I hope it will help ;)
The best answer seems to be a combination of RobbieE and Kuba:
You have to explicitly set the parent of the member variable in constructor. The parent-child feature is a Qt thing that exists among classes derived from QObject, it is not a feature of C++.
I never knew this - I assumed that when an object was created, its members variables automatically had their parent set to the object. Good to know!!
I want to inform an object when a thread has finished running. However, I cannot get the thread to exit properly. I have the following code:
Processor.cpp
thread = new QThread;
tw = new ThreadWorker;
connect(tw, SIGNAL(updateStatus(QString)), this, SLOT(statusUpdate(QString)));
tw->doSetup(thread, strDic);
tw->moveToThread(thread);
thread->start();
while(thread->isRunning())
{
}
qDebug() << "Thread Finished";
ThreadWorker.cpp
void ThreadWorker::doSetup(QThread *thread, const string &path)
{
_strPath = path;
connect(thread, SIGNAL(started()), this, SLOT(run()));
connect(this, SIGNAL(finished()), thread, SLOT(quit())); //tried terminate() also
}
void ThreadWorker::run()
{
DirectorySearch dicSearch;
vector<string> vecFileList = dicSearch.getFileList(_strPath);
emit updateStatus("Directory Fetched");
emit finished();
}
The quit() slot does not seem to stop the thread (QThread::isFinished never returns true). Can someone guide me in the right direction?
(Note: ThreadWorker does not inherit from QThread)
Assuming that Processor.cpp is running in your main thread, the while(thread->isRunning()) loop has your main thread completely tied up. This means that your application's event loop cannot do any processing so the signalupdateStatus() for example, will never get processed. As mentioned in the comments, since the QThread object is created by the main thread, its signals won't work either since they will also require the main event loop to be doing its thing. Besides, if you are waiting in your main thread for your worker thread to do something, why use a worker thread at all? :)
Try removing the while loop, add a slot workDone() (or whatever you want to call it) to Processor.cpp and connect that to your Threadworker's finished() signal.
I had the same problem and found the answer. Here is my question:
What is the use of QThread.wait() function?
To solve your problem, you don't need to run the QCoreApplication::instance()->processEvents() in your while loop, what you need to do is, instead of invoking the quit() which tries to send a signal to your creating thread's event loop (which is now blocked by the while loop), you have to call it directly.
So for your code, drop the line:
connect(this, SIGNAL(finished()), thread, SLOT(quit())); //tried terminate() also
And instead of:
emit finished();
Use:
this->thread()->quit();
Tada... problem solved. Lesson learned: don't try to exit a worker thread by the qt signal-slot mechanism from within it, because your signals do not end up where they are supposed to (your worker thread's event loop), but they end up in the creating thread instead. You never know what that thread is doing, and if its event loop is running or not, and this shouldn't be of business to your worker thread anyways... Instead, call the quit directly.
You can use Qt::DirectConnection:
connect(this, SIGNAL(finished()), thread, SLOT(quit()), Qt::DirectConnection);
This stops the thread.
Instead of doing your 'doSetup' function... before you moveToThread, setup connections between SINGALS on tw's parent and SLOTS in tw.
I would do 4 connections.
First is to the run method in ThreadWorker. Thats simple and self explainatory enough.
Second is from your finished signal to the third SIGNAL connection below. A SIGNAL that quits the thread
Third to a SIGNAL that should call the terminate() slot of the thread. This will effectively close the event loop setup when you connect to the run method (exec is auto called when you do a start()) and since your run method isn't a loop of some sort, will close the thread without issue.
Forth is from the thread's terminated() SIGNAL to a SLOT in tw's parent. This will show you when the thread is dead if you want to do something at that point.
You do the above connections (if you need to pass in the string, add a variable to the run method and corresponding SIGNAL connection and you'll have the data), move to thread, thread start, then do the SIGNAL attached to the run method. Let it do its thing. When its finished, it will do a finished signal that gets tied to another signal that gets tied to the threads terminated slot. This will kill the event loop and exit the thread, pushing a terminated signal out so you can then do something.