According to the documentation for Qt::ConnectionType in Qt5, using Qt::DirectConnection
means that the slot for a given signal is called in the same thread as the signal itself, even if the object the slot belongs to lies in a different thread.
In my application, I am creating a server, and when a new connection is received, I create a new thread, a new QWebSocket
object in it, and connect certain QWebSocket
signals to slots defined in the class of the server (the same class where the connection is received and the thread is created).
However, though the thread is created successfully, the slot is being called in the main thread.
Here is a simpler example that simulates what I am doing, an MCVE:
Base.h file:
#ifndef BASE_H
#define BASE_H
#include<QThread>
#include<thread>
#include<QObject>
#include "emitcaller.h"
#include <QDebug>
class Base : public QObject
{
Q_OBJECT
public:
EmitCaller *emitCaller;
void create_thread();
void make_emit();
public slots:
void do_something();
};
#endif // BASE_H
This represents the server class. create_thread()
is like the function when a new connection from a client is to be done. do_something()
is the slot that needs to be executed when the QWebSocket
receives a signal.
Base.cpp file:
#include "base.h"
#include "emitcaller.h"
#include<QEventLoop>
#include <mutex>
#include <condition_variable>
void Base::create_thread()
{
std::mutex mutex;
std::condition_variable cv;
std::thread t = std::thread([&](){
EmitCaller *ec = new EmitCaller;
this->emitCaller = ec;
qDebug() << "thread created, now in thread " << QThread::currentThread();
QObject::connect(ec,SIGNAL(my_signal()),this,SLOT(do_something()),Qt::DirectConnection);
cv.notify_all();
QEventLoop loop;
loop.exec();
});
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock); //wait till connect() completes, so that signal sent is received after that
t.detach();
}
void Base::do_something()
{
qDebug() << "doing something in thread " << QThread::currentThread();
}
void Base::make_emit()
{
qDebug() << "called make_emit in thread " << QThread::currentThread();
emitCaller->do_emit();
}
Next, EmitCaller.h file:
#ifndef EMITCALLER_H
#define EMITCALLER_H
#include <QObject>
#include <QDebug>
class EmitCaller : public QObject
{
Q_OBJECT
public:
void do_emit();
signals:
void my_signal();
};
#endif // EMITCALLER_H
This is to simulate the QWebSocket
. The my_signal()
signal is the one that the QWebSocket
in the program receives to call the do_something()
slot. make_emit()
is an extra function, just to ask the signal to be emitted, created only for the sake of this simplified example.
EmitCaller.cpp file:
#include "emitcaller.h"
void EmitCaller::do_emit()
{
emit my_signal();
}
main.cpp file:
#include <QApplication>
#include "base.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Base b;
qDebug() << "main in thread " << QThread::currentThread();
b.create_thread();
b.make_emit();
return a.exec();
}
The output is as follows:
main in thread QThread(0xc20180)
thread created, now in thread QThread(0x7fb9680009e0)
called make_emit in thread QThread(0xc20180)
doing something in thread QThread(0xc20180)
Now, as per my understanding, the following happens:
create_thread()
is called. TheEmitCaller
object (QWebSocket
object) is created inside a new thread. Thus, the thread affinity of the object should be the new thread, and all signals sent from it should be from the new thread.connect()
is done usingQt::DirectConnection
. So, the slotdo_something()
should be called in this new thread, even though its class object,b
, lies in the main thread.do_emit()
is called on the object whose thread affinity is with the new thread, which should result in the behaviour expected as described above.
I expect the output to instead be:
main in thread QThread(0xc20180)
thread created, now in thread QThread(0x7fb9680009e0)
called make_emit in thread QThread(0xc20180)
doing something in thread QThread(0x7fb9680009e0)
A few additional points:
- In my server program, I don't have a pointer pointing to the
QWebSocket
object. However, the signal there is generated when a new client connects. To send the signal myself, I have created a pointer to access the object. - I need to use
std::thread
, I cannot useQThread
for this.
Why is the slot being called in the receiver's thread, instead of the emitter's thread, even though
Qt::DirectConnection
is used?If this is incorrect, where am I going wrong? (I am new to the signal-slot system of Qt).
If this cannot be done this way, how can I achieve the behaviour I want? I would like
do_something()
to run in a separate thread.
Thank you.