Qt - does a QTimer::timeout() signal result in a QEvent? - c++

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.

Related

QT - force an object to process incoming signals

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.

Qt - emit a signal from a c++ thread

I want to emit a signal from a C++ thread (std::thread) in Qt.
How can I do it?
You definitely can emit a signal from a thread (QThread, std::thread or even boost::thread). Only you must be careful of your connect function's fifth parameter (Qt::ConnectionType):
If Qt::DirectConnection: The slot is invoked immediately (from the current thread), when the signal is emitted.
If Qt::QueuedConnection: The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
See ConnectionType-enum for more options.
The problem is not really from which thread you emit the signal, it's more from which thread the slot is being invoked. For instance, I think QLabel::setText must be executed from QLabel's owner thread (most likely main thread). So if you emit a signal connected to a QLabel's setText from a thread, connection must be done with Qt::AutoConnection, Qt::QueuedConnection or Qt::BlockingQueuedConnection.
You probably should not emit a Qt signal from a std::thread-created thread in general without care. See Jpo38's answer : connection type matters, etc...
If the thread is running some Qt event loop, you probably could. See threads and QObject
There is a (Unix-specific probably) work-around, doing the same as for Unix signals with Qt : use a pipe from your std::thread to the main thread.
But, as commented by Joachim Pileborg, you should make your own QThread. It is the simplest, and probably the shortest (in term of source code), and you just need to copy and paste some existing example and adapt it to your need.
Beware that AFAIK only the main thread should do Qt GUI manipulations. You should not use any QWidget (etc...) outside of the main thread! (BTW, GTK has the same restriction, at least on Linux: only the main thread is supposed to use the X Windows system protocols)
If you're keeping pointer to your QObject then you could use one of QMetaObject::invokeMethod member http://qt-project.org/doc/qt-5/qmetaobject.html#invokeMethod
Probably you will have to use Qt::QueuedConnection so your signal will be invoked at proper thread (not your std::thread). Remember that your signal won't be invoked immedietly.
class MainForm : public QMainWindow
{
Q_OBJECT
public:
explicit MainForm(QWidget *parent = nullptr);
virtual ~MainForm();
private:
signals:
void signalSendButtonEnable(bool);
private slots:
void singalReceiveButtonEnable(bool);
};
MainForm::MainForm(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainForm), status_{false}, io_context_{}, timer_{io_context_}
{
ui->setupUi(this);
// bind SIGNAL & SLOT
connect(this, SIGNAL(signalSendButtonEnable(bool)), this, SLOT(singalReceiveButtonEnable(bool)));
}
MainForm::~MainForm()
{
delete ui;
}
void MainForm::singalReceiveButtonEnable(bool status){ //recv signal
qDebug() << "singalReceiveButtonEnable";
this->ui->btnConnect->setEnabled(status);
}
void MainForm::start(){
std::thread t([](){
sleep(20);
emit signalSendButtonEnable(true); //send signal
});
t.detach();
}

QTimer in worker thread

I have a Worker class which does some work in another thread, where it's placed using moveToThread(). Inside Worker::doWork() method I also create a QTimer which is supposed to emit progress updates, based on the estimated time the task will take.
Here's an example:
ThreadController::ThreadController()
{
Worker* worker = new Worker;
worker->moveToThread(&m_workerThread);
// ...
m_workerThread.start();
emit startWorker(params); // connected to Worker::doWork()
}
class Worker : public QObject
{
Q_OBJECT
public slots:
Worker::doWork(const QString& params)
{
QTimer* timer = new QTimer(this);
connect( timer, SIGNAL(timeout)), this, SLOT(updateProgress()) );
timer->start(estimateTaskLength() / 100);
// perform work...
}
}
Now this doesn't work as intended. The updateProgress() slot only starts being called AFTER the work has been completed.
When the timer expires, the timeout event is queued to the event queue of your worker QThread. However, your worker QThread is busy executing doWork(), so the event can't be processed. Once the thread completes the doWork, control returns the the QThread's event loop and the timeout event is executed.
The simplest approach to fixing this would be to manually invoke the event loop using QCoreApplication::processEvents() at certain intervals throughout the execution of doWork(). This will allow the QThread to execute the timeout event earlier.
Alternative, you can use a different thread to perform these estimations. If they are not too performance-intensive, you can even use the GUI/main thread. The GUI/main thread is expected to remain "responsive" to events (otherwise the application appears to hang) so it can process the timeout event in a timely manner.
This probably depends on the type of connection between Qtimer::timeout and this::updateProgress.
By default, its a Qt::AutoConnection, which means that the timeout signal will be queued until the receiving object is ready to handle it. I.e. after doWork is finished.
If you connect using
connect( timer, SIGNAL(timeout)), this, SLOT(updateProgress()), Qt::DirectConnection );
the timeout signal should be treated immediately. (Make sure to include necessary mutexes and stuff though, as this is a typical case where e.g. concurrent accesses may occur..)
( http://qt-project.org/doc/qt-4.8/qt.html#ConnectionType-enum )

Qt Thread object only sending signal as Qt:DirectConnection - why?

I have a class derived from QThread: class MyClass : public QThread
This class is connected with a slot of another object. Originally this was connected as Qt::AutoConnection. But then - as soon as the thread is started (MyClass::run()) - the signal is no longer "reaching the slot" (why?).
// connected before myObject->run()
s = QObject::connect(
_myObject, SIGNAL(signalLogMessage(const QString&, QtMsgType)),
this, SLOT(slotLogMessage(const QString&, QtMsgType)), Qt::DirectConnection);
My first idea was that I need to force Qt::QueuedConnection (this / _myObject will be cross threaded). In this case it does not work at all. Only Qt::DirectConnection works. After the thread is started, IMHO Qt::QueuedConnection is the correct choice (cross thread).
Any idea what is going wrong? The connection itself seems to be correct, otherwise it was not working at (mean even not with Qt::DirectConnection).
Edit 1: -- As of hyde's answer / Nikos' comment
As of right now I think hyde's answer / Nikos' comment are pointing out the root cause. My QThread is running it's own message loop for another application. This is the reason why it is running in its own thread and is basically an infinite loop
run() {
// exec(); // while not reached
while (_runMessageLoop && ...) {
hr = CallDispatch(.....);
if (hr== 0) QThread::msleep(100);
// QCoreApplication::processEvents();
}
}
Guess due to this infinite loop the Qt message loop is not running and no signal / slots are processed (is this correct?) When forcing Qt::DirectConnection the methods are called directly with no Qt message loop required, this might be the reason why this is the only connection type working.
The question is now, how can I combine the Qt and my own message loop (if this is feasible)? Cannot call exec() before the loop (because then it is in the Qt loop), and just the QCoreApplication::processEvents(); in "my loop" is still not working.
=> see new Question here: How to combine own message loop and Qt event loop?
Hard to say without seeing all the code, but it may be because of this:
QThread object itself is not the thread, it's the thread controller. Most importantly, QThread object's thread affinity should not be the thread it controls. If your thread runs Qt event loop, then it's best to avoid subclassing QThread. Instead, have your logic (inter-thread slots etc) in another QObject, which you move to the thread you created with moveToThread after creating it. Only real reason to subclass QThread is to override run() method with one which does not call exec().
Related reading:
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
Addition:
If you override QThread::run(), you have to call QThread::exec() there or event loop won't be running and no non-direct signal gets delivered to any QObject with that thread affinity. If you want to have your own event loop, that is possible, you just have to call QCoreApplication::processEvents() to process Qt events.

Knowing when a QThread's event loop has started from another thread

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.