QSignalSpy can not be used with threads - c++

I wrote a thread that executes a worker object. Everything works fine. Also the resulting signals are emitted as they should. Of course I took care of the usual mistakes regarding thread/object affinity.
Today I wrote an automated module test for those workers/threads. I created a QSignalSpy to wait for a signal that is emitted by the worker object (which was moved to the thread) like this:
QSignalSpy spy(worker, SIGNAL(Success()));
thread.ExecuteWorker();
QVERIFY(spy.wait()); // Error in this line
I am getting a well known error in the marked line:
QObject::killTimer: timers cannot be stopped from another thread
First I exepected an error on my side because some code in wait() was executed in the wrong thread. Then I found the following code in the implementation of QSignalSpy:
if (!QMetaObject::connect(obj, sigIndex, this, memberOffset, Qt::DirectConnection, 0))
{
qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
return;
}
This obviously means QSignalSpy uses DirectConnection all time and can not be used to monitor signals of objects living in different threads.
Why did they program it that way in Qt5.3? Is that a mistake or is it intended behaviour? How can I work around this limitation?

This is unfortunately a long-standing issue, more than six years to be fair:
QSignalSpy crashes if signal is emitted from worker thread
I met Jason at the Qt Contributor Summit a couple of years ago, but then he left Nokia not much after that as Nokia closed the Brisbane office where he was working. After that, there was not much contribution going on in this test module of Qt, sadly.
There was recently more discussion about it on the mailing list, too:
Why is QSignalSpy using Qt::DirectConnection?
The solution proposed by Roland was this that the maintainer, Thiago, also accepted:
if (thread() != QThread::currentThread())
{
QMetaObject::invokeMethod(this, "exitLoop", Qt::QueuedConnection);
return;
}
It is a bit of shame really that this did not go in before 5.4. Having said that, this will be fixed for Qt 5.4 as the change was merged:
Make QTestEventLoop::exitLoop() thread-safe

In order to make QSignalSpy work reliably across threads I use the following approach: I move the spy to the worker thread and I re-implement the wait function as follows:
#include <QSignalSpy>
#include <QTime>
struct ThreadsafeQSignalSpy : QSignalSpy
{
template <typename Func>
ThreadsafeQSignalSpy(const typename QtPrivate::FunctionPointer<Func>::Object *obj, Func signal0)
: QSignalSpy(obj, signal0)
{}
bool wait(int timeout)
{
auto origCount(count());
QTime timer;
timer.start();
while (count() <= origCount && timer.elapsed() < timeout)
QCoreApplication::instance()->processEvents(QEventLoop::AllEvents, timeout/10);
return count() > origCount;
}
};
void TestSuite::testFunction()
{
QThread thread;
...
ThreadsafeQSignalSpy spy;
spy.moveToThread(thread);
/// now wait should work
...
QVERIFY(spy.wait(1000));
}

Related

Getting a QTimer in a QtConcurrent to work Properly

I am currently attempting to get a QTimer to work and emit the appropriate signals when running in a separate Thread. I'm not sure what I should do in order to get the timeout() signal to be emitted.
When I try using QFuture and QFutureWatcher they do not ever throw their finished() signal as this thread never really ends, it just keeps looping.
I've looked at a number of other questions 1, 2, 3, 4, 5 to no avail.
This is what I currently have. Any advice would be greatly appreciated!
Foo.cpp
Foo::Foo() {
...
mcTimerForSpoilers = new QTimer(this);
connect(mcTimerForSpoilers, SIGNAL(timeout()), this, SLOT(queueDownloadOfSpoilerFile()), Qt::QueuedConnection);
QtConcurrent::run(this, &Foo::manageSpoilerTimer);
}
void Foo::manageSpoilerTimer() {
...
mcTimerForSpoilers->setInterval(5000); // 5 seconds
mcTimerForSpoilers->start();
}
void Foo::queueDownloadOfSpoilerFile() {
...
std::cerr << "Queue Download" << std::endl;
manageSpoilerTimer(); // Restart the timer
}
Your design is wrong. You call QtConcurrent::run(this, &Foo::manageSpoilerTimer);but a timer can only be started from its own thread.
Furthermore, you don't specify an interval, so the timer will keep firing continuously, but then you also keep on starting the timer every time it times out.
It is not clear what you really want to do. It looks like you don't know what you are doing.
I don't think QtConcurrent is a good candidate for downloads to begin with. It doesn't support progress tracking, pausing or cancelling which are all features that downloading stuff should use. You should instead go for a threaded QObject based worker, as described in this answer.

Pausing QThread's event dispatch loop

I have a multithreaded application written in C++ with Qt. Currently, my application works by having a QThread instance (I have NOT subclassed QThread) which uses the default run() implementation that just calls QThread's exec() method, which provides an event dispatch loop.
I call moveToThread on certain QObject subclasses which actually perform the work I want done in a separate thread. I tell these objects to do work using Qt's signals/slots mechanism. I stop the thread gracefully by informing my worker objects to stop their work, and then calling quit() and wait() on my thread. This all works very nicely.
However, I now want to implement the following scenario:
The user clicks e.g. the "X" button on my application, because they want to close it.
I don't want any new work to be started, so I pause the event dispatch thread. If the current event being dispatched continues running, that's fine.
I prompt the user, allowing them to either a) discard all remaining jobs and exit (using quit() andwait()` - this already works), or b) don't exit the application, but instead continue working (resume the thread).
My problem is that QThread doesn't seem to have a pause() method. I've seen various examples online which add one (like the answers to this question). The problem is that these examples depend on having a custom run() implementation, and implementing pause there. Since I'm relying on QThread's event dispatch loop, these solutions won't work. I've considered doing something like reimplementing exec() or creating my own subclass of QAbstractEventDispatcher, but these solutions seem like a whole lot of work to get simple pause / resume functionality.
What's the easiest way to pause QThread's event dispatch loop (preventing it from dispatching any new events, but letting the current event continue)?
I tried out the method suggested in the comments, but it took a bit of screwing around to get it to work totally correctly, so here's what I ended up with:
I subclassed QThread to add two new methods: pause and resume. There were a few things that needed to be dealt with delicately:
Calling start() while the thread is still running does nothing. Since resume() might be called before the thread's existing job stops running, we need to do the actual resume in a slot connected to the thread's finished() signal.
The finished() signal may be emitted just before the thread actually stops. Because of this, we need to call wait() in our slot before calling start().
If resume() is called after the thread is already stopped, simply setting state variables won't work, because finished() will never be emitted. Because of this, we need to deal with that case by having non-signal-related resume code in the resume() method as well.
Here's the final product.
pausablethread.h:
#ifndef INCLUDE_PAUSABLE_THREAD_H
#define INCLUDE_PAUSABLE_THREAD_H
#include <QThread>
class QMutex;
class PausableThread : public QThread
{
Q_OBJECT
public:
PausableThread(QObject *parent = 0);
virtual ~PausableThread();
void pause();
void resume();
private:
QMutex *controlMutex;
bool paused;
bool resumeScheduled;
private Q_SLOTS:
void doResume();
};
#endif
pausablethread.cpp:
#include "pausablethread.h"
#include <QMutex>
#include <QMutexLocker>
PausableThread::PausableThread(QObject *parent)
: QThread(parent), paused(false), resumeScheduled(false)
{
controlMutex = new QMutex(QMutex::NonRecursive);
QObject::connect(this, SIGNAL(finished()),
this, SLOT(doResume()));
}
PausableThread::~PausableThread()
{
delete controlMutex;
}
void PausableThread::pause()
{
QMutexLocker locker(controlMutex);
if(paused)
return;
paused = true;
quit();
}
void PausableThread::resume()
{
QMutexLocker locker(controlMutex);
if(!paused)
return;
if(resumeScheduled)
return;
if(isFinished())
{
start();
paused = false;
resumeScheduled = false;
}
else
{
resumeScheduled = true;
}
}
void PausableThread::doResume()
{ /* SLOT */
QMutexLocker locker(controlMutex);
if(!resumeScheduled)
return;
paused = false;
resumeScheduled = false;
wait();
start();
}
This seems to work, mostly. I believe there are some potential race conditions if the thread happens to finish or start at the same time execution is inside resume() or doResume() in a different thread. It's not exactly clear to me how to solve this.
I tried something like overriding the superclass's start() slot with the following:
void start(Priority priority)
{
QMutexLocker locker(controlMutex);
QThread::start(priority);
}
The problem with this is that start() never actually returns until the thread finishes, so it never releases its lock on the mutex. Thus, when doResume() tries to acquire a lock, a deadlock is encountered, and the thread isn't successfully resumed.
I think what is really needed is a mutex which is exclusively locked any time the thread's running state is changed, but it isn't clear to me how to implement this.
Regardless, the window for this race to occur is very small,and this works "well enough" to answer my question. Thanks to #Lol4t0 for the suggestion!

Multi-threading in Qt problematic?

I have been learning Qt for a while and a few days ago I decided to go on multi-threading by QThread. I have been following this person. Since he says that subclassing QThread is not the appropriate way but by using QObject is. I am following his method. But he has created another class which inherits from QObject. I decided to make a few changes:
class myclass
{
private:
dowork();
private slots:
slota();
slotb();
slotc();
}
myclass::dowork()
{
QThread lett;
QThread latt;
QThread pltt;
QObject lethread;
connect(&lett, SIGNAL(started()), this, SLOT(slota()));
lethread.moveToThread(&lett);
QObject lathread;
connect(&latt, SIGNAL(started()), this, SLOT(slotb()));
lathread.moveToThread(&latt);
QObject plthread;
connect(&pltt, SIGNAL(started()), this, SLOT(slotc()));
plthread.moveToThread(&pltt);
lett.start();
latt.start();
pltt.start();/*
lett.wait();
latt.wait();
pltt.wait();*/
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
}
If I run the program it keeps running while loop infinitely! It doesn't come out of that at all.
I used qdebug inside the implementation of the 3 slots to check whether it is entering them or not, and surprisingly none of the slots gets called. Why is that so?
If I remove the comments for .wait then the program pauses.
What is wrong in this method? I want to avoid that extra class as my program is very small.
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
Terribly wrong. The current thread is busy waiting and will be eating all the time. But this is not your problem. Your problem is certainly that the main event loop has probably not started yet, ie you didn't do QApplication.exec() yet.
Qt uses events to start threads, and when you do use movetoThread, start, specific events are queued in the current thread (ie the thread executing these methods). If the main event loop has already started, then will be processed as soon as they can. But in your case I bet that you main function is :
int main(){
QApplication app();
myclass onlyclassIwanttomake;
onlyclassIwanttomake.dowork();
app.exec(); <----HERE!!!
}
The thread will be started when the main thread executes app.exec();. When you are busy waiting, you are preventing the main thread to process the events required to start your
events.
EDIT: Well, another issue is that
lett.start();
latt.start();
pltt.start();
start 3 threads which are started, and stay idle forever. They are not doing anything, but they are running (even if you remove your loop).
This is a entry written about Qt threading. Please take the time to read it.

start doesn't invoke run

I'm trying to implement some small app which is a gui app and has some heavy work to do as a one of it's main tasks. Obviously I'm putting this "work" into a separate thread and starting this thread by invoking start fnc on this obj. Unfortunatelly nothing happens. On the other hands when instead of start I invoke implemented fnc run computations are performed as they should although of course in same thread as gui. What to do?
So I have class inheriting QThread:
class Working_Thread : public QThread
{
Q_OBJECT
public:
typedef boost::filesystem3::path path_t;
private:
bool& cancel_flag_;
const std::set<path_t>& paths_;
int search_depth_;
typedef void (Dir_File_Select_Dialog::*fnc_ptr)(const std::set<path_t>&,int);
fnc_ptr fnc_;
Dir_File_Select_Dialog* parent_;
protected:
void run()
{
(parent_->*fnc_)(paths_,search_depth_);
}
public:
Working_Thread(bool& cancel_flag,const std::set<path_t>&,int&,fnc_ptr fnc,Dir_File_Select_Dialog* parent);
};
And here is fragment from gui thread when I try to start new thread:
Working_Thread* working_thread = new Working_Thread(cancel_flag,paths,search_depth,&Dir_File_Select_Dialog::extract_files_,this);
working_thread->start();//this desn't invoke run fnc
but when I do:
working_thread->run();//this will perform computations although in gui thread
UPDATE:
Little change I did which now performs computations when using start fnc but it still blocks GUI.
Working_Thread* working_thread = new Working_Thread(cancel_flag,paths,search_depth,&Dir_File_Select_Dialog::extract_files_,this);
working_thread->start();//hangs
working_thread->wait();//when I call wait here computation is performed but GUI is blocked.
I don't know how your code is actually done, but as a first step i suggest you to follow the best practice suggested at the end of the new revision of the Qt documentation of QThread :
http://qt-project.org/doc/qt-4.8/QThread.html (look for bottom of this page)
For a similar tutorial you also may check this article: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
Every time i tried to directly make my treatment in a QThread I ended up having big problems with threads (most of time, the treatment beeing done in the caller's tread).
This documentation has been added in 4.8 and the examples provided by documentation of previous versions were missleading.
(code copied from the Qt documentation)
Consider the following pattern as your default way to use QThread:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork() {
/* ... */
}
};
/* ... */
QThread *thread = new QThread;
Worker *worker = new Worker;
//obj is a pointer to a QObject that will trigger the work to start. It could just be this
connect(obj, SIGNAL(startWork()), worker, SLOT(doWork()));
worker->moveToThread(thread);
thread->start();
//obj will need to emit startWork() to get the work going.
Alternatively, you could do:
//based on the same Worker class as above:
/* ... */
QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
It is normal that the GUI blocks if you call wait() on a thread, because this will wait for the thread to finish, and also you haven't specified any timeout for wait in this case.
Now regarding the initial problem (when you don't call wait()), I have used QThread successfully in similar scenarios. I do not know though what is wrong in your code, but what I would check is if your execution doesn't hang in other places, like in the invocation of
(parent_->*fnc_)(paths_,search_depth_);
So maybe inserting some log / debug message before and after this call, and also in the function that is invoke here might help isolating the problem. At least then you'll know if the run() method is invoked or not. For example:
qDebug() << "In thread.run()";
(parent_->*fnc_)(paths_,search_depth_);
qDebug() << "In thread.run(), calculations are done";
Also I find it suspicious that you perform calculation using a GUI object (Dir_File_Select_Dialog). This is not normal in Qt, Gui objects should normally be used in the GUI thread. Why not implement the calculations directly in run? Or at least move it to a non-GUI object, just to be sure and keep GUI implementations separated from background operations.
If you call wait, the GUI is going to be blocked.
If this program hangs when you do a start, it seems that the problem is in this call: (parent_->*fnc_)(paths_,search_depth_);
You could place a qDebug call just before and after this call.

Connecting signals/slots on separate thread using QtConcurrent::run

In my application I have the following code in a dialog:
connect(drive, SIGNAL(FileProgressChanged(Progress)), SLOT(OnFileProgressChanged(Progress)));
QtConcurrent::run(this, &ProgressDialog::PerformOperation, Operation, *Path, OutPath, drive);
The PerformOperation function eventually calls to a function in drive which emits the signal FileProgressChanged, and my OnFileProgressChanged function is as follows:
void ProgressDialog::OnFileProgressChanged(Progress p)
{
if (ui->progressCurrent->maximum() != p.Maximium)
ui->progressCurrent->setMaximum(p.Maximium);
ui->progressCurrent->setValue(p.Current);
if (ui->groupBoxCurrent->title().toStdString() != p.FilePath)
ui->groupBoxCurrent->setTitle(QString::fromStdString(p.FilePath));
}
I was doing some reading and saw that QFuture and QFutureWatcher support monitoring progress values (which would work great in this situation!), but those cannot be used in conjunction with QtConcurrent::run.
How would I go about connecting the signal that gets moved emitted on the separate thread to the slot on my main thread so I can monitor the progress of the function called on the emitter thread?
*Edit -- * I actually found an error with my code, but it doesn't seem to have an affect. I forgot to add this as an argument after the signal
connect(drive, SIGNAL(FileProgressChanged(Progress)), this, SLOT(OnFileProgressChanged(Progress)));
Try using connect() with QueuedConnection, like:
connect(drive, SIGNAL(FileProgressChanged(Progress)), this, SLOT(OnFileProgressChanged(Progress)), Qt::QueuedConnection);
The connection should already be queued by default (since the emitter and receiver are in different threads), but this just makes it more explicit.
EDIT: The problem was that the Progress type wasn't registered with Qt's meta-object system. Adding qRegisterMetaType<Progress>("Progress"); fixed the problem.
It appears as though the problem isn't with the cross-thread signal/slot, but instead with the parameter Progress. This question's answer goes into further detail, but the solution was found by doing the following in the header file in which Progress was declared:
struct Progress
{
int Current;
int Maximium;
std::string FilePath;
std::string FolderPath;
int TotalMinimum;
int TotalMaximum;
};
Q_DECLARE_METATYPE(Progress)
And in my form class:
qRegisterMetaType<Progress>();
connect(Drive, SIGNAL(FileProgressChanged(const Progress&)), this, SLOT(OnFileProgressChanged(const Progress&)), Qt::QueuedConnection);
Changing Progress to const Progress& most likely isn't needed but I left it while testing.