Qt blocked event loop - c++

I recently started using the QT framework. Yesterday I began programming a simple multithreaded application. At the moment I'm somewhat stuck on the following problem.
Consider two worker classes that both use a thread to do some 'heavy computations'. The first class, FooWorker, looks like the following:
class FooWorker : public QObject
{
Q_OBJECT
public:
FooWorker() : QObject() { }
~FooWorker() { }
signals:
void notify(int);
void aborted();
public slots:
void doWork()
{
int counter = 0;
forever {
// For the sake of this example this reassembles a heavy computational process
if(counter++ < 10) {
emit notify(counter);
QThread::sleep(1);
} else {
counter = 0;
// Wait until we get a signal to restart the process
mutex_.lock();
condition_.wait(&mutex_);
mutex_.unlock();
}
// We should check for a cancellation flag every iteration...
}
emit aborted();
}
private:
QMutex mutex_;
QWaitCondition condition_;
};
The slot 'doWork' will be scheduled to run in another thread. The slot will run forever and is emitting a signal every second until 10 notifications are emitted. After that we wait until it is woken up again.
The second class, BarWorker, looks like this:
class BarWorker : public QObject
{
Q_OBJECT
public:
BarWorker() : QObject() { }
~BarWorker() { }
signals:
void aborted();
public slots:
void doWork()
{
forever {
// Another heavy computational process
QThread::sleep(1);
// We should check for a cancellation flag every iteration...
}
emit aborted();
}
void onNotify(int value)
{
qDebug() << "Notification value:" << value;
}
};
Again the slot 'doWork' will be scheduled to run in another thread. The slot will run forever to do a heavy computational process. Again once the process is done we will wait until it is woken up again (for the sake of this example I left that out in this class).
Finally the main looks like the following:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread* barThread = new QThread();
BarWorker* barWorker = new BarWorker();
barWorker->moveToThread(barThread);
QThread* fooThread = new QThread();
FooWorker* fooWorker = new FooWorker();
fooWorker->moveToThread(fooThread);
// Automatically deletes worker and thread
QObject::connect(fooThread, SIGNAL(started()), fooWorker, SLOT(doWork()));
QObject::connect(fooWorker, SIGNAL(aborted()), fooThread, SLOT(quit()));
QObject::connect(fooWorker, SIGNAL(aborted()), fooWorker, SLOT(deleteLater()));
QObject::connect(fooThread, SIGNAL(finished()), fooThread, SLOT(deleteLater()));
QObject::connect(barThread, SIGNAL(started()), barWorker, SLOT(doWork()));
QObject::connect(barWorker, SIGNAL(aborted()), barThread, SLOT(quit()));
QObject::connect(barWorker, SIGNAL(aborted()), barWorker, SLOT(deleteLater()));
QObject::connect(barThread, SIGNAL(finished()), barThread, SLOT(deleteLater()));
QObject::connect(fooWorker, SIGNAL(notify(int)), barWorker, SLOT(onNotify(int)), Qt::QueuedConnection);
fooThread->start();
barThread->start();
return a.exec();
}
When I run the application nothing gets printed. That was to be expected because the event loop of the BarWorker instance is blocked. As the 'notify' signal gets emitted the 'onNotify' slot is queued onto the event queue. Because we have a never ending loop (until we manually abort it) in the 'doWork' slot, the 'onNotify' slot will not be called. To solve this I can do a couple of things, namely:
Connect the 'notify' signal to the 'onNotify' slot by using the Qt::DirectConnection flag. This way it looks like a normal function call executing on the signalling thread.
Occasionally call the QCoreApplication::processEvents() method to force the event queue to be processed.
Unknown solution I do not know at this time :)???
I hope someone has some alternative solution to this problem, or even suggest an entire different approach, because IMHO above solutions are somewhat ugly and do not feel right.

I don't think there is any "magic" solution to be found here; a thread can't be running Qt's event loop if it is running your own custom event loop. In practice, there are two common solutions, which are really two sides of the same coin:
Call processEvents() periodically from your event loop, as you suggested in your question, so that the Qt event-handling code occasionally gets to run and handle incoming asynchronous signals.
Don't have a long-running loop in your doWork() method. Instead, do a short amount of work, store the results/state of that work in a member variable or somewhere, and then call something like QTimer::singleShot(0, this, SLOT(doWork())) so that the Qt event loop will call your doWork() method again soon after the first call to doWork() returns. That way the Qt event loop never gets held off for longer than the (brief) period of time taken up by a single doWork() call.
Of those two options, I think the second is preferable, because it allows the Qt event loop to run in its normal fashion, and it also avoids a potential tripping-over-your-own-shoelaces issue -- e.g. imagine if while using solution (1) your call to processEvents() causes a slot to be called that deletes the BarWorker object. When the processEvents() call returns, BarWorker::doWork() will resume executing, but at that point, all of the local member variables and virtual methods it might access as part of its normal execution have been destroyed, and reading or writing them will cause undefined behavior (if you're lucky, an easy-to-debug crash). That possible snafu can't happen when using solution (2), since if the BarWorker object gets deleted between calls to doWork(), any queued-up asynchronous call to doWork() will be safely cancelled.

The idiom for a forever loop that interoperates with the event loop is a zero-duration timer. We can factor it out into a WorkerBase class, where the unit of work is to be done in the workUnit method:
// https://github.com/KubaO/stackoverflown/tree/master/questions/worker-timer-40369716
#include <QtCore>
// See http://stackoverflow.com/q/40382820/1329652
template <typename Fun> void safe(QObject * obj, Fun && fun) {
Q_ASSERT(obj->thread() || qApp && qApp->thread() == QThread::currentThread());
if (Q_LIKELY(obj->thread() == QThread::currentThread()))
return fun();
struct Event : public QEvent {
using F = typename std::decay<Fun>::type;
F fun;
Event(F && fun) : QEvent(QEvent::None), fun(std::move(fun)) {}
Event(const F & fun) : QEvent(QEvent::None), fun(fun) {}
~Event() { fun(); }
};
QCoreApplication::postEvent(
obj->thread() ? obj : qApp, new Event(std::forward<Fun>(fun)));
}
class WorkerBase : public QObject {
Q_OBJECT
QBasicTimer timer_;
protected:
virtual void workUnit() = 0;
void timerEvent(QTimerEvent *event) override {
if (event->timerId() == timer_.timerId() && timer_.isActive())
workUnit();
}
public:
using QObject::QObject;
Q_SIGNAL void finished();
/// Thread-safe
Q_SLOT void virtual start() {
safe(this, [=]{
timer_.start(0, this);
});
}
/// Thread-safe
Q_SLOT void virtual stop() {
safe(this, [=]{
if (!isActive()) return;
timer_.stop();
emit finished();
});
}
bool isActive() const { return timer_.isActive(); }
~WorkerBase() {
if (isActive()) emit finished();
}
};
The workers then become:
class FooWorker : public WorkerBase
{
Q_OBJECT
int counter = 0;
bool isDone() const { return counter >= 10; }
void workUnit() override {
if (!isDone()) {
counter ++;
emit notify(counter);
QThread::sleep(1);
} else
stop();
}
public:
void start() override {
counter = 0;
WorkerBase::start();
}
void stop() override {
if (!isDone()) emit aborted();
WorkerBase::stop();
}
Q_SIGNAL void notify(int);
Q_SIGNAL void aborted();
};
class BarWorker : public WorkerBase
{
Q_OBJECT
void workUnit() override {
QThread::sleep(1);
}
public:
void stop() override {
emit aborted();
WorkerBase::stop();
}
Q_SIGNAL void aborted();
Q_SLOT void onNotify(int value)
{
qDebug() << "Notification value:" << value;
}
};
Note that the aborted() and finished() signals have different meanings.
Finally, the test harness:
class Thread : public QThread { public: ~Thread() { quit(); wait(); } };
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
BarWorker barWorker;
FooWorker fooWorker;
Thread barThread, fooThread;
barWorker.moveToThread(&barThread);
fooWorker.moveToThread(&fooThread);
barWorker.start();
fooWorker.start();
QObject::connect(&fooWorker, &FooWorker::finished, &app, &QCoreApplication::quit);
QObject::connect(&fooWorker, &FooWorker::notify, &barWorker, &BarWorker::onNotify);
fooThread.start();
barThread.start();
return app.exec();
}
#include "main.moc"
If you get a QBasicTimer::stop: Failed. Possibly trying to stop from a different thread warning, it's of no consequence and is a result of a Qt bug.

Related

Should I call processEvents() on a thread?

QThread documentation suggests two ways to make code run in a separate thread. If I use moveToThread approach, I have to call processEvents() to issue the timeouts, to have the lambda executed. And this seems to cost a lot of CPU. Why is so?
class Worker : public QObject
{
Q_OBJECT
QTimer* timer;
bool m_abort = false;
public:
Worker() {}
void abort() {m_abort = true;}
public slots:
void run() {
timer = new QTimer;
connect(timer, &QTimer::timeout, []{qDebug() << "computed";});
timer->start(1000);
forever {
if (m_abort) break;
QCoreApplication::processEvents();
}
}
};
class MainWidget : public QWidget
{
Q_OBJECT
QThread thread;
Worker* worker;
public:
MainWidget()
{
worker = new Worker;
worker->moveToThread(&thread);
connect(this, &MainWidget::start, worker, &Worker::run);
thread.start();
emit start();
}
~MainWidget(){worker->abort(); thread.quit(); thread.wait();}
signals:
void start();
};
However if I subclass QThread and reimplement run() it's not necessary to call processEvents. And CPU cost seems lower. Why?
class Worker : public QThread
{
public:
Worker() {}
protected:
void run() override {
QTimer timer;
connect(&timer, &QTimer::timeout, []{qDebug() << "computed";});
timer.start(1000);
exec();
}
};
class MainWidget : public QWidget
{
Q_OBJECT
Worker* worker;
public:
MainWidget()
{
worker = new Worker;
worker->start();
}
};
your run() function 'blocks' the thread. It is being invoked in the thread context, but never returns. This means, the event loop in the thread doesn't get executed anymore as soon as your run() funtion is called.
For the timer events to call your lambdas, the event loop has to be processed.
If you would modify your run function like this:
void run() {
timer = new QTimer(this);
connect(timer, &QTimer::timeout, []{qDebug() << "computed";});
timer->start(1000);
// don't loop here, instead exit the function
// and let the thread return back to the event loop
}
then your lambdas should get called. The thread will also keep running until you call thread.quit()
note: you can also connect directly to the '''started''' signal of the thread:
connect(&thread, &QThread::started, worker, &Worker::run);
thread.start();
moveToThread approach might be improved by calling run() function just after thread emit started.
But I still don't know why the way I put it initially doesn't work.

Local QEventLoop - waiting for a signal from thread - prevent processing events from main event loop

I have problem with waiting in 'network' thread for a signal from 'io' thread.
In io_thread.cpp I have:
void io_thread::run()
{
app_log = new app_logger();
room_log_mgr = new room_logger_manager(this);
emit init_finished();
exec();
QCoreApplication::processEvents();
delete room_log_mgr;
delete app_log;
}
In 'main' thread I have two queued events (do_something1 and do_something2 executes in 'network' thread):
QMetaObject::invokeMethod(network_obj, "do_something1", Qt::QueuedConnection);
QMetaObject::invokeMethod(network_obj, "do_something2", Qt::QueuedConnection);
In do_something1 method I have this code:
QEventLoop loop;
QObject::connect(&logger_thread, &io_thread::init_finished, &loop, &QEventLoop::quit, Qt::BlockingQueuedConnection);
logger_thread.start();
loop.exec();
So I waiting for init_finished signal from io_thread and loop.exec() should block 'network' thread from executing. But when program execute loop.exec() then immediately switch to executing do_something2, and after do_something2 has finished program execution backs to do_something1 after line loop.exec().
It's looks like local event loop processing more events that I have expected.
I want to wait for a &io_thread::init_finished signal without processing other events in local event loop. How can I do that?
The event loop processes all events that are available: your expectation is incorrect. How can the event loop divine that you would like to "suspend" some event? It can't.
What you really want - but you wrote it backwards - is for the network management thread to start once the I/O manager is done initializing. That way nothing has to wait for anything!
Waiting for things happens when you write pseudosynchronous code, and that's the source of all your woes. Do not spin event loops manually. Do not inherit from QThread (other than to make it RAII).
Finally, it'd be nice if neither the io_manager nor network_manager needed special code to handle the fact that they are in their own threads.
First, we need to include functor dispatch code from this answer.
// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-sync-50188307
#include <QtCore>
namespace detail { template <typename F> struct FEvent : QEvent {
const QObject *const obj;
const QMetaObject *const type = obj->metaObject();
typename std::decay<F>::type fun;
template <typename Fun>
FEvent(const QObject *obj, Fun &&fun) :
QEvent(QEvent::None), obj(obj), fun(std::forward<Fun>(fun)) {}
~FEvent() { // ensure that the object is not being destructed
if (obj->metaObject()->inherits(type)) fun();
}
}; }
template <typename F> static void post(QObject *obj, F &&fun) {
Q_ASSERT(!qobject_cast<QThread*>(obj));
QCoreApplication::postEvent(obj, new detail::FEvent<F>(obj, std::forward<F>(fun)));
}
Then, we need a true RAII thread that's always safe to destruct:
class Thread final : public QThread {
Q_OBJECT
void run() override {
if (!eventDispatcher())
QThread::run();
}
public:
using QThread::QThread;
using QThread::exec;
~Thread() override {
requestInterruption();
quit();
wait();
}
template <typename F> void on_start(F &&fun) {
connect(this, &QThread::started, std::forward<F>(fun));
}
};
The started signal is emitted within the thread, and any functors passed to on_start effectively become injected into the thread. The run() method is reimplemented to only start an event loop if one wasn't previously running. This way we can inject entire thread bodies that construct objects and spin the event loop.
The I/O and network manager are simple objects, not threads. We defer the construction of the io_manager and network_manager to their respective threads. That way, the individual objects don't have to be aware of what thread they run on.
#include <memory>
using app_logger = QObject;
using room_logger_manager = QObject;
class io_manager : public QObject {
Q_OBJECT
app_logger app_log{this};
room_logger_manager room_log_mgr{this};
public:
using QObject::QObject;
};
class network_manager : public QObject {
Q_OBJECT
public:
network_manager(QObject *parent = {}) : QObject(parent) {
do_something1();
do_something2();
}
void do_something1() { qDebug() << __FUNCTION__; }
void do_something2() { qDebug() << __FUNCTION__; qApp->quit(); }
};
int main(int argc, char *argv[]) {
QCoreApplication app{argc, argv};
QPointer<io_manager> iomgr; //optional
QPointer<network_manager> netmgr; //optional
Thread io_thread, network_thread;
io_thread.on_start([&]{
qDebug() << "I/O thread is running.";
io_manager mgr;
iomgr = &mgr;
network_thread.start();
io_thread.exec();
});
network_thread.on_start([&]{
qDebug() << "Network thread is running.";
network_manager mgr;
netmgr = &mgr;
network_thread.exec();
});
io_thread.start();
return app.exec(); // RAII all the way!
}
#include "main.moc"
Output:
I/O thread is running.
Network thread is running.
do_something1
do_something2
Notice how the lifetime of all objects is handled automatically.

Custom function interrupt

Is it possible to implement function interrupt in Qt (5.x).
For example if I have a button and want something to execute on the thread (which is running infinite loop) when this button is clicked, I could say something like this:
in thread...
forever
{
if(button_is_pressed_flag)
{
do something...
}
}
is there a better way?
The infinite loop should be an event loop, and then it can automatically process cross-thread slot calls without you worrying about the details.
The idiom to run code "continuously" on an event loop is the zero-duration timer.
Let's say you start with code that looks like this:
class MyThread : public QThread {
bool button_is_clicked_flag = false;
void run() override {
forever{
if (button_is_clicked_flag) {
onButtonClick();
button_is_clicked_flag = false;
}
doWork();
}
}
void onButtonClick();
void doWork();
public:
using QThread::QThread;
void setButtonClickedFlag();
}
int main(int argc, char **argv) {
...
MyThread t;
t.start();
...
}
It is required for doWork() not to take too long - nor too short. If it took ~5ms on modern hardware, it'd be just about a right tradeoff between overhead and latency for a general-purpose application. If you need lower latency reaction in the worker thread, then doWork() must do less work. It probably doesn't make much sense for doWork() to take much less than 1ms.
And whenever doWork() doesn't have anything to do, e.g. if it's done with the computation it was supposed to perform, it should stop the timer that keeps it alive.
You should transform it to look as follows:
class MyWorker : public QObject {
Q_OBJECT
QBasicTimer m_timer;
void doWork();
void timerEvent(QTimerEvent *event) {
if (event->timerId() == m_timer.timerId())
doWork();
}
public:
explicit MyWorker(QObject *parent = nullptr) : QObject(parent) {
m_timer.start(0, this);
}
Q_SLOT void onButtonClick() {
// Ensure we're invoked correctly
Q_ASSERT(QThread::currentThread() == thread());
...
}
}
class Window : public QWidget {
Ui::Window ui;
public:
Q_SIGNAL void buttonClicked();
explicit Window(QWidget *parent = nullptr) : QWidget(parent) {
ui.setupUi(this);
connect(ui.button, &QPushButton::clicked, this, &Window::buttonClicked);
}
};
class SafeThread : public QThread {
Q_OBJECT
using QThread::run; // final method
public:
~SafeThread() { quit(); wait(); } // we're safe to destroy - always
};
int main(int argc, char **argv) {
...
MyWorker worker;
SafeThread thread;
Window window;
// onButtonClick will be executed in worker->thread()
connect(&window, &Window::buttonClicked, &worker, &MyWorker::onButtonClick);
worker.moveToThread(&thread);
thread.start();
window.show();
return app.exec();
}
The event loop that runs in QThread::run will continuously invoke doWork via the timer event handler. But whenever a cross-thread slot call needs to be made to an object living in that thread, the event loop will deliver the internal QMetaCallEvent representing the slot call to QObject::event, which will then execute the call.
Thus, when you set a breakpoint in onButtonClick, there will be QObject::event nearby on the call stack.
You could start a thread and then immediately wait on a std::condition_variable, then when the button is clicked (the event being called on the main thread), notify the condition variable and the thread would awake.
However, this is a bit strange. What are you trying to do? call an asynchronous task upon a button click? In that case, perhaps it would be better just to start one from the button click event with std::packaged_task or std::async.

Wait for several objects to emit a signal

I know how to wait for a single object to finish, using
QEventLoop eventLoop;
connect(&obj, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
But now I have several objects which I want to 'run' in parallel, so I need to wait until all of them have sent their finished() SIGNALs.
This would be like a signals-and-slots version of the WaitForMultipleObjects WinApi function.
How should I go about doing that?
I would connect the finished signal to a class that counts the # of signals received and emits quit() when it hits the expected count.
Something like this:
class EmitIfCountReached : public QObject
{
Q_OBJECT
public:
EmitIfCountReached( int expectedCount, QObject* parent = nullptr) : m_expected(expectedCount), m_count(0), QObject(parent) {}
signals:
void finished();
protected slots:
void increment() {
m_count++;
if (m_count >= m_expected) {
emit finished();
}
}
protected:
int m_count;
int m_expected;
};

QThread and QTimer

I'm working on an application developed with Qt 4.6.
I want to create a custom timer that counts in a separate thread. However, I want this timer to be able to send signals to the main thread.
I subclassed QThread but it doesn't seem to work.
Here is Timer.h:
#ifndef TIMER_H
#define TIMER_H
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QTimer>
class Timer : public QThread
{
Q_OBJECT
public:
explicit Timer(QObject *parent = 0);
~Timer();
// true if the timer is active
bool isCounting();
// start the timer with a number of seconds
void startCounting(int value = 300);
void stopCounting();
// the number of seconds to reach
int maximum();
// the current value of the timer
int value();
// elapsed time since the timer has started
int elapsedTime();
signals:
// sent when the timer finishes to count
void timeout();
// an event is emited at each second when the timer is active
void top(int remainingSeconds);
protected:
// launch the thread
//virtual void run();
private slots:
// decrements the remaining time at each second and emits top()
void timerEvent();
private:
QTimer* _timer;
// remaining time
int _left;
// number of seconds at timer startup
int _maximum;
};
#endif // TIMER_H
And Timer.cpp:
#include "Timer.h"
Timer::Timer(QObject *parent) :
QThread(parent)
{
_timer = new QTimer(this);
_maximum = 0;
_left = 0;
connect(_timer, SIGNAL(timeout()), this, SLOT(timerEvent()));
}
Timer::~Timer()
{
delete _timer;
}
bool Timer::isCounting()
{
// test if timer still active
return _timer->isActive();
}
void Timer::startCounting(int value)
{
qDebug() << QString("Start timer for %1 secs").arg(QString::number(value));
if(_left != 0 || _timer->isActive())
{
_timer->stop();
}
_maximum = value;
_left = value;
// emit the first top
emit top(_left);
// start the timer: 1000 msecs
_timer->start(1000);
// start the thread
start();
}
void Timer::stopCounting()
{
qDebug() << QString("Stopping timer at %1 secs => %2 secs remaining.").arg(QString::number(elapsedTime()), QString::number(_left));
// stop timer
_timer->stop();
_left = 0;
_maximum = 0;
// kill thread
terminate();
}
int Timer::maximum()
{
return _maximum;
}
int Timer::value()
{
return _left;
}
void Timer::timerEvent()
{
qDebug() << "Timer event";
if(--_left == 0)
{
// stop timer
_timer->stop();
// emit end of timer
emit timeout();
// stop thread
terminate();
}
else
{
// emit a signal at each second
emit top(_left);
}
}
int Timer::elapsedTime()
{
return (_maximum - _left);
}
EDIT
I realized the object I tried to move to another thread was actually a singleton. It could lead to a problem (see here).
You don't need to subclass QThread in this particular case. And in general, abstain from subclassing QThread unless you are sure it is what you need.
Here is a quick example how to setup a worker and timer in a thread and launch it:
the worker class:
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0) : QObject(parent) {}
signals:
void doSomething();
public slots:
void trigger() {
emit doSomething();
}
};
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MainThreadObject o;
QThread *thread = new QThread;
Worker w;
QTimer timer;
timer.setInterval(1000);
timer.moveToThread(thread);
w.moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), &timer, SLOT(start()));
QObject::connect(&w, SIGNAL(doSomething()), &o, SLOT(doSomething()));
QObject::connect(&timer, SIGNAL(timeout()), &w, SLOT(trigger()));
thread->start();
return a.exec();
}
So, we have the MainThreadObject which represents a QObject derived living in the main thread. We create the timer and Worker object, which is just used to wrap a signal and slot to avoid the need of subclassing QThread. The timer is setup and it and the worker are moved to the new thread, the thread started() signal is connected to the timer start() slot, the worker doSomething() signal is connected to the main thread object doSomething() slot, and finally the timer timeout() signal is connected to the worker trigger() slot. Then the thread is started which initiates the entire chain in the event loop.
As a result, the MainThreadObject::doSomething() is called every second, with the signal emitted from the secondary thread.
Try
QMetaObject::invokeMethod(&timer, "start", Qt::QueuedConnection); //timer->start()
if you want to start timer immediately
Or
QMetaObject::invokeMethod(&timer, "start", Qt::QueuedConnection , Q_ARG(int, 1000 )); //timer->start(200)
if you want to start timer after 1000s
In the Non-GUI thread (QThread or Pthread Callback)
First, if you subclass from QThread, you have to implement run() method, if not, there is no point of doing that, you can inherit from QObject instead.
Second, your QTimer has to reside in a thread that runs an event loop. Without an event loop no Qt queued signals can be transmitted. You can launch an event loop by calling exec() in thread's run method:
void Timer::run() {
exec();
}
Probable reason can be, your timer object is not in a thread with event loop. Event loop is required to trigger the signals.
However, I would suggest that you should not go with this approach. Timers use different mechanism on different platform and your code might not behave as expected on different platform.