Signal Slot Communication Time Over Queued Connection
-
uncertainty in QT signal and slot communication mechanism time over the queued connection. My signal and slot (respective objects) live in two different threads, As part of the benchmark signals is emitting from a Worker thread to the Slot in the Main thread. The signal emitting rate is 60 per second. The main thread is running in an event loop and the worker thread keeps on emitting signals. In my scenario, the Main thread is completely ideal and the slot contains only the return statement (so expecting an immediate return from the slot). I measured the time taken for signal-slot communication and plotted a graph on resulted data. I found these were some deep spikes intermittently and even communication time also not linear as I thought.
Benchmark Code:
Renderer.h
#pragma once #include <QObject> #include <fstream> #include <iostream> using namespace std; class Renderer : public QObject { Q_OBJECT public: Renderer(); ~Renderer(); private: fstream mFileLogger; public slots: void onDisplayImage(void* frame); };Renderer.cpp
#include "Renderer.h" Renderer::Renderer() { mFileLogger.open("Renderer.log", ios::out); if (!mFileLogger) { cout << "Failed to create log file" << endl; } } Renderer::~Renderer() {} void Renderer::onDisplayImage(void* frame) { auto slotTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); mFileLogger << "slot recieved time " << slotTime << endl; }Producer.h
#pragma once #include <QObject> #include <fstream> #include <iostream> #include <QThread> using namespace std; class Producer : public QObject { Q_OBJECT private: void mImageMaker(); fstream mFileLogger; public: Producer(); ~Producer(); signals: void displayImage(void* frame); public slots: void start(); };Producer.cpp
#include "Producer.h" Producer::Producer() { mFileLogger.open("Producer.log", ios::out); if (!mFileLogger) { cout << "Failed to create Producer log file" << endl; } } Producer::~Producer() { } void Producer::mImageMaker() { while (true) { auto signalTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); mFileLogger << "signal emit time " << signalTime << endl; emit displayImage({}); QThread::msleep(16); } } void Producer::start() { cout << "Producer start invoked" << endl; mImageMaker(); }Server.cpp
#include <thread> #include <fstream> #include <qthread.h> #include "Renderer.h" #include "Producer.h" using namespace std; int main(int argc, char* argv[]) { QApplication *qtApp = new QApplication(argc, argv); Renderer* renderer = new Renderer(); Producer* producer = new Producer(); QThread workerThread; //workerThread.setObjectName("Producer_Thread"); producer->moveToThread(&workerThread); workerThread.start(); QObject::connect(producer, &Producer::displayImage, renderer, &Renderer::onDisplayImage); QMetaObject::invokeMethod(producer, "start"); qtApp->exec(); cout << "Returning from Main" << endl; return 0; }Plotted signal slot communication timings over a period of time.

-
uncertainty in QT signal and slot communication mechanism time over the queued connection. My signal and slot (respective objects) live in two different threads, As part of the benchmark signals is emitting from a Worker thread to the Slot in the Main thread. The signal emitting rate is 60 per second. The main thread is running in an event loop and the worker thread keeps on emitting signals. In my scenario, the Main thread is completely ideal and the slot contains only the return statement (so expecting an immediate return from the slot). I measured the time taken for signal-slot communication and plotted a graph on resulted data. I found these were some deep spikes intermittently and even communication time also not linear as I thought.
Benchmark Code:
Renderer.h
#pragma once #include <QObject> #include <fstream> #include <iostream> using namespace std; class Renderer : public QObject { Q_OBJECT public: Renderer(); ~Renderer(); private: fstream mFileLogger; public slots: void onDisplayImage(void* frame); };Renderer.cpp
#include "Renderer.h" Renderer::Renderer() { mFileLogger.open("Renderer.log", ios::out); if (!mFileLogger) { cout << "Failed to create log file" << endl; } } Renderer::~Renderer() {} void Renderer::onDisplayImage(void* frame) { auto slotTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); mFileLogger << "slot recieved time " << slotTime << endl; }Producer.h
#pragma once #include <QObject> #include <fstream> #include <iostream> #include <QThread> using namespace std; class Producer : public QObject { Q_OBJECT private: void mImageMaker(); fstream mFileLogger; public: Producer(); ~Producer(); signals: void displayImage(void* frame); public slots: void start(); };Producer.cpp
#include "Producer.h" Producer::Producer() { mFileLogger.open("Producer.log", ios::out); if (!mFileLogger) { cout << "Failed to create Producer log file" << endl; } } Producer::~Producer() { } void Producer::mImageMaker() { while (true) { auto signalTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); mFileLogger << "signal emit time " << signalTime << endl; emit displayImage({}); QThread::msleep(16); } } void Producer::start() { cout << "Producer start invoked" << endl; mImageMaker(); }Server.cpp
#include <thread> #include <fstream> #include <qthread.h> #include "Renderer.h" #include "Producer.h" using namespace std; int main(int argc, char* argv[]) { QApplication *qtApp = new QApplication(argc, argv); Renderer* renderer = new Renderer(); Producer* producer = new Producer(); QThread workerThread; //workerThread.setObjectName("Producer_Thread"); producer->moveToThread(&workerThread); workerThread.start(); QObject::connect(producer, &Producer::displayImage, renderer, &Renderer::onDisplayImage); QMetaObject::invokeMethod(producer, "start"); qtApp->exec(); cout << "Returning from Main" << endl; return 0; }Plotted signal slot communication timings over a period of time.

@g-suresh Signals across thread are put into the queue of the receiving thread and then on next iteration of the event loop in that thread next signal is fetched and the slot called. So, there are no guarantees on when exactly the slot will be called. If you need more deterministic behaviour you will need to call methods in the other thread directly and synchronise.
-
@g-suresh Signals across thread are put into the queue of the receiving thread and then on next iteration of the event loop in that thread next signal is fetched and the slot called. So, there are no guarantees on when exactly the slot will be called. If you need more deterministic behaviour you will need to call methods in the other thread directly and synchronise.
@jsulm Thanks for your explanation. I understood that the main thread event loop will actually pick the signal from Queue on its next iteration. But If you see my benchmark code the slot returns immediately and the main thread not doing any other task so I assume the event loop immediately picks the next signal in Queue but this is not happening. Can you clarify why the main thread event loop not scheduling immediately? And
Can you please point me link or material on how to invoke methods directly across threads in QT without using signal slot/Event loop at all. -
@jsulm Thanks for your explanation. I understood that the main thread event loop will actually pick the signal from Queue on its next iteration. But If you see my benchmark code the slot returns immediately and the main thread not doing any other task so I assume the event loop immediately picks the next signal in Queue but this is not happening. Can you clarify why the main thread event loop not scheduling immediately? And
Can you please point me link or material on how to invoke methods directly across threads in QT without using signal slot/Event loop at all.@g-suresh said in Signal Slot Communication Time Over Queued Connection:
Can you please point me link or material on how to invoke methods directly across threads in QT without using signal slot/Event loop at all.
Nothing Qt specific here: simply call a method of the other class living in another thread. But then you need to consider two things:
- You have to do synchronisation if needed
- You are not allowed to manipulate the UI from other threads, only from main/GUI thread
"so I assume the event loop immediately picks the next signal" - it picks the next signal next time the event loop is activated. When the event loop is activated and how often I don't know.