Qt 5: emit signal from non-Qt thread - c++

What I am trying to achieve is a cross-platform TCP socket library built on top of Qt QTcpServer/Socket. I faced an issue that signals, emitted from a non-Qt thread without Qt event loop, are not received by objects in QThread with the event loop.
I have found that emitting from a non-Qt thread worked before with Qt::QueuedConnection connection type set explicitly, according to this and this questions. Those questions are rather old and relate to Qt 4. So I wonder if this functionality is still supported in Qt 5.
I have explored the Qt 5 source code and found:
Emitting a signal is just a call to QMetaObject::activate
QMetaObject::activate, in turn, calls queued_activate, if connection type is set to Qt::QueuedConnection or the current thread (emitter thread) is different from the thread receiver lives in (in my case, Qt::QueuedConnection is set explicitly).
queued_activate creates an event object and calls QCoreApplication::postEvent
QCoreApplication::postEvent does proper locking and puts the event into the receiver event queue. Despite postEvent is a static QCoreApplication function that uses self - a pointer to current static QCoreApplication singleton, it should work properly even if there is no global QCoreApplication object (i.e. self == 0).
Given this, I suppose that for signal&slot mechanism to work properly, only the receiver thread has to have the Qt event loop that will dispatch the event from the queue, correct me if I am wrong.
Despite that, emitting a signal from a non-Qt thread does not work for me. I have created as simple demo app as possible that demonstrates the malfunctioning of the signal&slot.
MyThread component just inherits QThread and moves inside itself (moveToThread) QObject-derived ThreadWorker.
MyThread.h:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include "ThreadWorker.h"
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread();
signals:
void mySignal();
private:
ThreadWorker m_worker;
};
#endif // MYTHREAD_H
MyThread.cpp:
#include "MyThread.h"
#include "ThreadWorker.h"
MyThread::MyThread()
: m_worker(*this)
{
m_worker.moveToThread(this);
}
Thread worker is needed to live in MyThread thread and to connect to MyThread`s mySignal() signal.
ThreadWorker.h:
#ifndef THREADWORKER_H
#define THREADWORKER_H
#include <QObject>
class MyThread;
class ThreadWorker : public QObject
{
Q_OBJECT
public:
explicit ThreadWorker(const MyThread& thread);
public slots:
void mySlot();
};
#endif // THREADWORKER_H
ThreadWorker.cpp:
#include "ThreadWorker.h"
#include <QDebug>
#include "MyThread.h"
ThreadWorker::ThreadWorker(const MyThread& thread)
: QObject(0)
{
connect(&thread, SIGNAL(mySignal()),
this, SLOT(mySlot()),
Qt::QueuedConnection);
}
void ThreadWorker::mySlot()
{
qDebug() << "mySlot called! It works!";
}
Finally, the main.cpp:
#include <QCoreApplication>
#include <QDebug>
#include "MyThread.h"
int main(int argc, char *argv[])
{
// QCoreApplication a(argc, argv);
MyThread my_thread;
my_thread.start();
emit my_thread.mySignal();
qDebug() << "mySignal emitted";
my_thread.wait();
// return a.exec();
}
Note, that if I uncomment QCoreApplication creation, I get the correct output:
mySignal emitted
mySlot called! It works!
but if I leave it as is, I get only
mySignal emitted
QEventLoop: Cannot be used without QApplication
So, what is the reason signal&slot mechanism does not work in this case? How to make it working?

The error message tells you exactly what you need to know: you can't use the event loop system without QCoreApplication existing. That's all. All of your exploration into the innards of Qt was educational, but a red herring. None if it matters at all.
only the receiver thread has to have the Qt event loop that will dispatch the event from the queue
That's correct.
Does it mean that if I create QCoreApplication inside QThread, this system should work?
You might create it on any thread (in contrast to QGuiApplication that can only live on the main thread). But make sure that you link statically with Qt. Otherwise, if you're linking with system Qt, you'll become binary incompatible with any process using the same Qt if you create a second instance of the application. Thus, if you use system Qt you can work around by inspecting whether an application instance exists, and only create one if it doesn't exist yet.
Furthermore, you shouldn't really need to create the application instance in a custom thread. Your library should accept an initialization call that should be performed in the main thread of the calling process. This initialization can create an application object if one doesn't exist.
// https://github.com/KubaO/stackoverflown/tree/master/questions/twothreads-41044526
#include <QtCore>
// see http://stackoverflow.com/questions/40382820
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 Worker : public QObject {
Q_OBJECT
QBasicTimer m_timer;
int n = 0;
void timerEvent(QTimerEvent *event) override {
if (event->timerId() == m_timer.timerId())
emit hasData(n++);
}
public:
Q_SIGNAL void hasData(int);
Q_SLOT void onData(int d) { qDebug() << QThread::currentThread() << "got data" << d; }
void start() {
safe(this, [this]{ m_timer.start(50,this); });
}
void quit() {
safe(this, [this]{ m_timer.stop(); thread()->quit(); });
}
};
class Library {
QByteArray dummy{"dummy"};
int argc = 1;
char *argv[2] = {dummy.data(), nullptr};
QScopedPointer<QCoreApplication> app;
static Library *m_self;
struct {
Worker worker;
QThread thread;
} m_jobs[3];
public:
Library() {
Q_ASSERT(!instance());
m_self = this;
if (!qApp) app.reset(new QCoreApplication(argc, argv));
for (auto & job : m_jobs) {
job.worker.moveToThread(&job.thread);
job.thread.start();
job.worker.start();
QObject::connect(&job.worker, &Worker::hasData, &m_jobs[0].worker, &Worker::onData);
}
}
~Library() {
for (auto &job : m_jobs) {
job.worker.quit();
job.thread.wait();
}
}
static Library *instance() { return m_self; }
};
Library *Library::m_self;
// API
void initLib() {
new Library;
}
void finishLib() {
delete Library::instance();
}
int main()
{
initLib();
QThread::sleep(3);
finishLib();
}
#include "main.moc"

Related

Why is this thread slot not getting called?

Two.h
#ifndef TWO_H
#define TWO_H
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QTimer>
class Two : public QObject
{
Q_OBJECT
private:
QTimer abc;
public:
QString m_xyz;
Two();
signals:
void emitThisSignal( int x, QString &y );
public slots:
void mySlot();
};
class Controller : public QObject
{
Q_OBJECT
private:
Two objTwo;
QThread objQThread;
Controller();
public slots:
void mySlot( int x, QString &y)
{
qDebug() << "\nWWWWWWWWWWWWW: " << y;
}
};
#endif // TWO_H
Two.cpp
#include "two.h"
Two::Two()
{
m_xyz = "aksja";
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Two::mySlot);
timer->start(1000);
}
void Two::mySlot()
{
emit emitThisSignal(4, m_xyz);
qDebug()<< "FFFFFFFFFFF " << m_xyz;
}
Controller::Controller()
{
objTwo.moveToThread( &objQThread );
connect( &objTwo, &Two::emitThisSignal, this, &Controller::mySlot );
connect( &objQThread, &QThread::finished, &objQThread, &QThread::deleteLater );
objQThread.start();
}
Controller::~Controller()
{
delete objTwo;
objQThread.wait();
}
I can see that the signal is being emitted because of the print statement but the slot of the Controller class is not getting called.
void Two::mySlot()
{
emit emitThisSignal(4, m_xyz);
qDebug()<< "FFFFFFFFFFF " << m_xyz;
}
Why is that so?
int main( int argc, char* argv[])
{
QCoreApplication app(argc, argv);
Controller o;
return app.exec();
}
See documentation of QObject::connect, note last argument with default value: Qt::AutoConnection.
Its documentation says:
(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
Now you are fall in into Qt::QueuedConnection scenario:
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.
So basically you need something which will provide an event loop.
In this code you need that:
int main( int argc, char* argv[])
{
QCoreApplication app{argc, argv};
Controller o;
// note you need something what will stop this event loop to terminate application
return app.exec();
}
One more thing.
Now I noticed that your signals and slot argument is quite unusual. Problem might be second argument which type is QString&.
It might be source of problems I do not know if Qt is able to marshal non const references. If you will add const then it will be able to marshal QString and should work (if I didn't missed other pitfall).

How to invoke slot for object in another thread without using connect? [duplicate]

In ObjC with GCD, there is a way of executing a lambda in any of the threads that spin an event loop. For example:
dispatch_sync(dispatch_get_main_queue(), ^{ /* do sth */ });
or:
dispatch_async(dispatch_get_main_queue(), ^{ /* do sth */ });
It executes something (equivalent to []{ /* do sth */ } in C++) in the main thread's queue, either blocking or asynchronously.
How can I do the same in Qt?
From what I have read, I guess the solution would be somehow to send a signal to some object of the main thread. But what object? Just QApplication::instance()? (That is the only object living in the main thread at that point.) And what signal?
From the current answers and my current research, it really seems that I need some dummy object to sit in the main thread with some slot which just waits to get in some code to execute.
So, I decided to subclass QApplication to add that. My current code, which doesn't work (but maybe you can help):
#include <QApplication>
#include <QThread>
#include <QMetaMethod>
#include <functional>
#include <assert.h>
class App : public QApplication
{
Q_OBJECT
public:
App();
signals:
public slots:
void genericExec(std::function<void(void)> func) {
func();
}
private:
// cache this
QMetaMethod genericExec_method;
public:
void invokeGenericExec(std::function<void(void)> func, Qt::ConnectionType connType) {
if(!genericExec_method) {
QByteArray normalizedSignature = QMetaObject::normalizedSignature("genericExec(std::function<void(void)>)");
int methodIndex = this->metaObject()->indexOfSlot(normalizedSignature);
assert(methodIndex >= 0);
genericExec_method = this->metaObject()->method(methodIndex);
}
genericExec_method.invoke(this, connType, Q_ARG(std::function<void(void)>, func));
}
};
static inline
void execInMainThread_sync(std::function<void(void)> func) {
if(qApp->thread() == QThread::currentThread())
func();
else {
((App*) qApp)->invokeGenericExec(func, Qt::BlockingQueuedConnection);
}
}
static inline
void execInMainThread_async(std::function<void(void)> func) {
((App*) qApp)->invokeGenericExec(func, Qt::QueuedConnection);
}
It is certainly possible. Any solution will center on delivering an event that wraps the functor to a consumer object residing in the desired thread. We shall call this operation metacall posting. The particulars can be executed in several ways.
Qt 5.10 & up TL;DR
// invoke on the main thread
QMetaObject::invokeMethod(qApp, []{ ... });
// invoke on an object's thread
QMetaObject::invokeMethod(obj, []{ ... });
// invoke on a particular thread
QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread),
[]{ ... });
TL;DR for functors
// https://github.com/KubaO/stackoverflown/tree/master/questions/metacall-21646467
// Qt 5.10 & up - it's all done
template <typename F>
static void postToObject(F &&fun, QObject *obj = qApp) {
QMetaObject::invokeMethod(obj, std::forward<F>(fun));
}
template <typename F>
static void postToThread(F && fun, QThread *thread = qApp->thread()) {
auto *obj = QAbstractEventDispatcher::instance(thread);
Q_ASSERT(obj);
QMetaObject::invokeMethod(obj, std::forward<F>(fun));
}
// Qt 5/4 - preferred, has least allocations
namespace detail {
template <typename F>
struct FEvent : public QEvent {
using Fun = typename std::decay<F>::type;
Fun fun;
FEvent(Fun && fun) : QEvent(QEvent::None), fun(std::move(fun)) {}
FEvent(const Fun & fun) : QEvent(QEvent::None), fun(fun) {}
~FEvent() { fun(); }
}; }
template <typename F>
static void postToObject(F && fun, QObject * obj = qApp) {
if (qobject_cast<QThread*>(obj))
qWarning() << "posting a call to a thread object - consider using postToThread";
QCoreApplication::postEvent(obj, new detail::FEvent<F>(std::forward<F>(fun)));
}
template <typename F>
static void postToThread(F && fun, QThread * thread = qApp->thread()) {
QObject * obj = QAbstractEventDispatcher::instance(thread);
Q_ASSERT(obj);
QCoreApplication::postEvent(obj, new detail::FEvent<F>(std::forward<F>(fun)));
}
// Qt 5 - alternative version
template <typename F>
static void postToObject2(F && fun, QObject * obj = qApp) {
if (qobject_cast<QThread*>(obj))
qWarning() << "posting a call to a thread object - consider using postToThread";
QObject src;
QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun),
Qt::QueuedConnection);
}
template <typename F>
static void postToThread2(F && fun, QThread * thread = qApp->thread()) {
QObject * obj = QAbstractEventDispatcher::instance(thread);
Q_ASSERT(obj);
QObject src;
QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun),
Qt::QueuedConnection);
}
void test1() {
QThread t;
QObject o;
o.moveToThread(&t);
// Execute in given object's thread
postToObject([&]{ o.setObjectName("hello"); }, &o);
// or
postToObject(std::bind(&QObject::setObjectName, &o, "hello"), &o);
// Execute in given thread
postToThread([]{ qDebug() << "hello from worker thread"; });
// Execute in the main thread
postToThread([]{ qDebug() << "hello from main thread"; });
}
TL;DR for methods/slots
// Qt 5/4
template <typename T, typename R>
static void postToObject(T * obj, R(T::* method)()) {
struct Event : public QEvent {
T * obj;
R(T::* method)();
Event(T * obj, R(T::*method)()):
QEvent(QEvent::None), obj(obj), method(method) {}
~Event() { (obj->*method)(); }
};
if (qobject_cast<QThread*>(obj))
qWarning() << "posting a call to a thread object - this may be a bug";
QCoreApplication::postEvent(obj, new Event(obj, method));
}
void test2() {
QThread t;
struct MyObject : QObject { void method() {} } obj;
obj.moveToThread(&t);
// Execute in obj's thread
postToObject(&obj, &MyObject::method);
}
TL;DR: What about a single shot timer?
All of the above methods work from threads that don't have an event loop. Due to QTBUG-66458, the handy appropriation of QTimer::singleShot needs an event loop in the source thread as well. Then postToObject becomes very simple, and you could possibly just use QTimer::singleShot directly, although it's an awkward name that hides the intent from those unfamiliar with this idiom. The indirection via a function named to better indicate the intent makes sense, even if you don't need the type check:
template <typename F>
static void postToObject(F && fun, QObject * obj = qApp) {
if (qobject_cast<QThread*>(obj))
qWarning() << "posting a call to a thread object - consider using postToThread";
QTimer::singleShot(0, obj, std::forward<F>(fun));
}
Common Code
Let's define our problem in terms of the following common code. The simplest solutions will post the event to either the application object, iff the target thread is the main thread, or to an event dispatcher for any other given thread. Since the event dispatcher will exist only after QThread::run has been entered, we indicate the requirement for the thread to be running by returning true from needsRunningThread.
#ifndef HAS_FUNCTORCALLCONSUMER
namespace FunctorCallConsumer {
bool needsRunningThread() { return true; }
QObject * forThread(QThread * thread) {
Q_ASSERT(thread);
QObject * target = thread == qApp->thread()
? static_cast<QObject*>(qApp) : QAbstractEventDispatcher::instance(thread);
Q_ASSERT_X(target, "postMetaCall", "the receiver thread must have an event loop");
return target;
}
}
#endif
The metacall posting functions, in their simplest form, require the functor call consumer to provide object for a given thread, and instantiate the functor call event. The implementation of the event is still ahead of us, and is the essential difference between various implementations.
The second overload takes a rvalue reference for the functor, potentially saving a copy operation on the functor. This is helpful if the continuation contains data that is expensive to copy.
#ifndef HAS_POSTMETACALL
void postMetaCall(QThread * thread, const std::function<void()> & fun) {
auto receiver = FunctorCallConsumer::forThread(thread);
QCoreApplication::postEvent(receiver, new FunctorCallEvent(fun, receiver));
}
void postMetaCall(QThread * thread, std::function<void()> && fun) {
auto receiver = FunctorCallConsumer::forThread(thread);
QCoreApplication::postEvent(receiver,
new FunctorCallEvent(std::move(fun), receiver));
}
#endif
For demonstration purposes, the worker thread first posts a metacall to the main thread, and then defers to QThread::run() to start an event loop to listen for possible metacalls from other threads. A mutex is used to allow the thread user to wait in a simple fashion for the thread to start, if necessitated by the consumer's implementation. Such wait is necessary for the default event consumer given above.
class Worker : public QThread {
QMutex m_started;
void run() {
m_started.unlock();
postMetaCall(qApp->thread(), []{
qDebug() << "worker functor executes in thread" << QThread::currentThread();
});
QThread::run();
}
public:
Worker(QObject * parent = 0) : QThread(parent) { m_started.lock(); }
~Worker() { quit(); wait(); }
void waitForStart() { m_started.lock(); m_started.unlock(); }
};
Finally, we start the above worker thread that posts a metacall to the main (application) thread, and the application thread posts a metacall to the worker thread.
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.thread()->setObjectName("main");
Worker worker;
worker.setObjectName("worker");
qDebug() << "worker thread:" << &worker;
qDebug() << "main thread:" << QThread::currentThread();
if (FunctorCallConsumer::needsRunningThread()) {
worker.start();
worker.waitForStart();
}
postMetaCall(&worker, []{ qDebug() << "main functor executes in thread" << QThread::currentThread(); });
if (!FunctorCallConsumer::needsRunningThread()) worker.start();
QMetaObject::invokeMethod(&a, "quit", Qt::QueuedConnection);
return a.exec();
}
The output will look approximately as follows in all implementations. The functors cross the threads: the one created in the main thread is executed in the worker thread, and vice-versa.
worker thread: QThread(0x7fff5692fc20, name = "worker")
main thread: QThread(0x7f86abc02f00, name = "main")
main functor executes in thread QThread(0x7fff5692fc20, name = "worker")
worker functor executes in thread QThread(0x7f86abc02f00, name = "main")
Qt 5 Solution Using a Temporary Object as The Signal Source
The simplest approach for Qt 5 is to use a temporary QObject as a signal source, and connect the functor to its destroyed(QObject*) signal. When postMetaCall returns, the signalSource gets destructed, emits its destroyed signal, and posts the metacall to the proxy object.
This is perhaps the most concise and straightforward implementation in the C++11 style. The signalSource object is used in the C++11 RAII fashion for the side effects of its destruction. The phrase "side effects" has a meaning within C++11's semantics and should not be interpreted to mean "unreliable" or "undesirable" - it's anything but. QObject's contract with us is to emit destroyed sometime during the execution of its destructor. We're more than welcome to use that fact.
#include <QtCore>
#include <functional>
namespace FunctorCallConsumer { QObject * forThread(QThread*); }
#define HAS_POSTMETACALL
void postMetaCall(QThread * thread, const std::function<void()> & fun) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed,
FunctorCallConsumer::forThread(thread), [=](QObject*){ fun(); });
}
#ifdef __cpp_init_captures
void postMetaCall(QThread * thread, std::function<void()> && fun) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed,
FunctorCallConsumer::forThread(thread), [fun(std::move(fun))](QObject*){ fun(); });
}
#endif
// Common Code follows here
If we only intend to post to the main thread, the code becomes almost trivial:
void postToMainThread(const std::function<void()> & fun) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed, qApp, [=](QObject*){
fun();
});
}
#ifdef __cpp_init_captures
void postToMainThread(std::function<void()> && fun) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed, qApp, [fun(std::move(fun))](QObject*){
fun();
});
}
#endif
Qt 4/5 Solution Using QEvent Destructor
The same approach can be applied to QEvent directly. The event's virtual destructor can call the functor. The events are deleted right after they are delivered by the consumer object's thread's event dispatcher, so they always execute in the right thread. This will not change in Qt 4/5.
#include <QtCore>
#include <functional>
class FunctorCallEvent : public QEvent {
std::function<void()> m_fun;
QThread * m_thread;
public:
FunctorCallEvent(const std::function<void()> & fun, QObject * receiver) :
QEvent(QEvent::None), m_fun(fun), m_thread(receiver->thread()) {}
FunctorCallEvent(std::function<void()> && fun, QObject * receiver) :
QEvent(QEvent::None), m_fun(std::move(fun)), m_thread(receiver->thread()) { qDebug() << "move semantics"; }
~FunctorCallEvent() {
if (QThread::currentThread() == m_thread)
m_fun();
else
qWarning() << "Dropping a functor call destined for thread" << m_thread;
}
};
// Common Code follows here
To post to main thread only, things become even simpler:
class FunctorCallEvent : public QEvent {
std::function<void()> m_fun;
public:
FunctorCallEvent(const std::function<void()> & fun) :
QEvent(QEvent::None), m_fun(fun) {}
FunctorCallEvent(std::function<void()> && fun, QObject * receiver) :
QEvent(QEvent::None), m_fun(std::move(fun)) {}
~FunctorCallEvent() {
m_fun();
}
};
void postToMainThread(const std::function<void()> & fun) {
QCoreApplication::postEvent(qApp, new FunctorCallEvent(fun);
}
void postToMainThread(std::function<void()> && fun) {
QCoreApplication::postEvent(qApp, new FunctorCallEvent(std::move(fun)));
}
Qt 5 Solution Using the Private QMetaCallEvent
The functor can be wrapped in the Qt 5 slot object payload of the QMetaCallEvent. The functor will be invoked by QObject::event, and thus can be posted to any object in the target thread. This solution uses the private implementation details of Qt 5.
#include <QtCore>
#include <private/qobject_p.h>
#include <functional>
class FunctorCallEvent : public QMetaCallEvent {
public:
template <typename Functor>
FunctorCallEvent(Functor && fun, QObject * receiver) :
QMetaCallEvent(new QtPrivate::QFunctorSlotObject<Functor, 0, typename QtPrivate::List_Left<void, 0>::Value, void>
(std::forward<Functor>(fun)), receiver, 0, 0, 0, (void**)malloc(sizeof(void*))) {}
// Metacalls with slot objects require an argument array for the return type, even if it's void.
};
// Common Code follows here
Qt 4/5 Solution Using a Custom Event and Consumer
We reimplement the event() method of the object, and have it call the functor. This calls for an explicit event consumer object in each thread that the functors are posted to. The object is cleaned up when its thread is finished, or, for the main thread, when the application instance is destructed. It works on both Qt 4 and Qt 5. The use of rvalue references avoids copying of the temporary functor.
#include <QtCore>
#include <functional>
class FunctorCallEvent : public QEvent {
std::function<void()> m_fun;
public:
FunctorCallEvent(const std::function<void()> & fun, QObject *) :
QEvent(QEvent::None), m_fun(fun) {}
FunctorCallEvent(std::function<void()> && fun, QObject *) :
QEvent(QEvent::None), m_fun(std::move(fun)) { qDebug() << "move semantics"; }
void call() { m_fun(); }
};
#define HAS_FUNCTORCALLCONSUMER
class FunctorCallConsumer : public QObject {
typedef QMap<QThread*, FunctorCallConsumer*> Map;
static QObject * m_appThreadObject;
static QMutex m_threadObjectMutex;
static Map m_threadObjects;
bool event(QEvent * ev) {
if (!dynamic_cast<FunctorCallEvent*>(ev)) return QObject::event(ev);
static_cast<FunctorCallEvent*>(ev)->call();
return true;
}
FunctorCallConsumer() {}
~FunctorCallConsumer() {
qDebug() << "consumer done for thread" << thread();
Q_ASSERT(thread());
QMutexLocker lock(&m_threadObjectMutex);
m_threadObjects.remove(thread());
}
static void deleteAppThreadObject() {
delete m_appThreadObject;
m_appThreadObject = nullptr;
}
public:
static bool needsRunningThread() { return false; }
static FunctorCallConsumer * forThread(QThread * thread) {
QMutexLocker lock(&m_threadObjectMutex);
Map map = m_threadObjects;
lock.unlock();
Map::const_iterator it = map.find(thread);
if (it != map.end()) return *it;
FunctorCallConsumer * consumer = new FunctorCallConsumer;
consumer->moveToThread(thread);
if (thread != qApp->thread())
QObject::connect(thread, SIGNAL(finished()), consumer, SLOT(deleteLater()));
lock.relock();
it = m_threadObjects.find(thread);
if (it == m_threadObjects.end()) {
if (thread == qApp->thread()) {
Q_ASSERT(! m_appThreadObject);
m_appThreadObject = consumer;
qAddPostRoutine(&deleteAppThreadObject);
}
m_threadObjects.insert(thread, consumer);
return consumer;
} else {
delete consumer;
return *it;
}
}
};
QObject * FunctorCallConsumer::m_appThreadObject = nullptr;
QMutex FunctorCallConsumer::m_threadObjectMutex;
FunctorCallConsumer::Map FunctorCallConsumer::m_threadObjects;
// Common Code follows here
There are one new approach that is the easiest I think.
It`s from Qt 5.4. Link to documentation
void QTimer::singleShot(int msec, const QObject *context, Functor functor)
Example:
QTimer::singleShot(0, qApp, []()
{
qDebug() << "hi from event loop";
});
lambda will be executed in qApp thread(main thread). You could replace context with any QObject you want.
Updated
QTimer needs event loop to work. For Threads with no qt event loop(std::thread) we could create one. Code to run lambda in std::thread.
QEventLoop loop;
Q_UNUSED(loop)
QTimer::singleShot(0, qApp, []()
{
qDebug() << "singleShot from std thread";
});
Full example
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>
#include <thread>
#include <QThread>
#include <QEventLoop>
#include <QThread>
using std::thread;
class TestObj
:public QObject
{
// Used new connect syntax no need for Q_OBJECT define
// you SHOULD use it. I used just to upload one file
//Q_OBJECT
public slots:
void doWork()
{
qDebug() << "QThread id" << QThread::currentThreadId();
QTimer::singleShot(0, qApp, []()
{
qDebug() << "singleShot from QThread" << QThread::currentThreadId();
});
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "main thread id" << QThread::currentThreadId();
thread testThread([]()
{
QEventLoop loop;
Q_UNUSED(loop)
qDebug() << "std::thread id" << QThread::currentThreadId();
QTimer::singleShot(0, qApp, []()
{
qDebug() << "singleShot from std thread" << QThread::currentThreadId();
});
qDebug() << "std::thread finished";
});
testThread.detach();
QThread testQThread;
TestObj testObj;
testObj.moveToThread(&testQThread);
QObject::connect(&testQThread, &QThread::started, &testObj, &TestObj::doWork);
testQThread.start();
return a.exec();
}
May something like this be any useful?
template <typename Func>
inline static void MyRunLater(Func func) {
QTimer *t = new QTimer();
t->moveToThread(qApp->thread());
t->setSingleShot(true);
QObject::connect(t, &QTimer::timeout, [=]() {
func();
t->deleteLater();
});
QMetaObject::invokeMethod(t, "start", Qt::QueuedConnection, Q_ARG(int, 0));
}
This piece of code will make your lambda run on the main thread event loop as soon as it is possible.
No args support, this is a very basic code.
NOTE: I didn't test it properly.
Others have exelent answers. here is my suggest. instead of doing something like this:-
QMetaObject::invokeMethod(socketManager,"newSocket",
Qt::QueuedConnection,
Q_ARG(QString, host),
Q_ARG(quint16, port.toUShort()),
Q_ARG(QString, username),
Q_ARG(QString, passhash)
);
do something like this which is more nice:-
QMetaObject::invokeMethod(socketManager,[=](){
socketManager->newSocket(host,port.toUShort(),username,passhash);
},Qt::QueuedConnection);
I have absolutely no idea what your talking about, but I'm going to try to answer it any way.
Lets say your have a class with a slot fucntion
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass() {}
public slots:
void MySlot() { qDebug() << "RAWR";
};
So no if you want to run this synchronously in the main thread you can call that function directly. In order to connect a signal you need to create an object and connect a signal to the slot.
class MySignalClass : public QObject
{
Q_OBJECT
public:
MySignalClass() {}
signalSomthign() { emit someAwesomeSignal; }
public signals:
void someAwesomeSignal();
};
And somwhere in the main thread you do something like
MyClass slotClass;
MySignalClass signalClass;
qobject::connect(&signalClass, SIGNAL(someAwesomeSignal), &slotClass(), SLOT(MySlot)));
So now if something you can connect multiple signals to that slot object, but realisticly the code I provided won't run any different than a normal function call. You'll be able to see that with a stack trace. If you add the flag qobject::queuedConneciton to the connect then it will que the slot call in the event loop.
You can easily thread a signal as well, but this will automatically be a queuedConnection
MyClass slotClass;
MySignalClass signalClass;
QThread someThread;
slotClass.moveToThread(&someThread);
qobject::connect(&signalClass, SIGNAL(someAwesomeSignal), &slotClass(), SLOT(MySlot)));
Now you'll have a threaded signal basically. If your signal is going to be threaded then all you have to do is switch to signalClass.moveToThread(&someThread), when the signal is emitted signalClass will be run in the main thread.
If you don't want an object to be called, I'm not sure, lamdas might work. I've used them before but Ithink they still need to be wrapped up in a class.
qobject::connect(&signalClass, &slotClass::MySlot, [=]() { /* whatever */ });
Although I'm pretty sure with Qt5 you can even go as far as creating a slot in line within a connect. But once your using lambdas I have no idea how threads work with them. As far as I know you need an object to sit in a thread basically to force calling the slot from the main thread.

How to execute a functor or a lambda in a given thread in Qt, GCD-style?

In ObjC with GCD, there is a way of executing a lambda in any of the threads that spin an event loop. For example:
dispatch_sync(dispatch_get_main_queue(), ^{ /* do sth */ });
or:
dispatch_async(dispatch_get_main_queue(), ^{ /* do sth */ });
It executes something (equivalent to []{ /* do sth */ } in C++) in the main thread's queue, either blocking or asynchronously.
How can I do the same in Qt?
From what I have read, I guess the solution would be somehow to send a signal to some object of the main thread. But what object? Just QApplication::instance()? (That is the only object living in the main thread at that point.) And what signal?
From the current answers and my current research, it really seems that I need some dummy object to sit in the main thread with some slot which just waits to get in some code to execute.
So, I decided to subclass QApplication to add that. My current code, which doesn't work (but maybe you can help):
#include <QApplication>
#include <QThread>
#include <QMetaMethod>
#include <functional>
#include <assert.h>
class App : public QApplication
{
Q_OBJECT
public:
App();
signals:
public slots:
void genericExec(std::function<void(void)> func) {
func();
}
private:
// cache this
QMetaMethod genericExec_method;
public:
void invokeGenericExec(std::function<void(void)> func, Qt::ConnectionType connType) {
if(!genericExec_method) {
QByteArray normalizedSignature = QMetaObject::normalizedSignature("genericExec(std::function<void(void)>)");
int methodIndex = this->metaObject()->indexOfSlot(normalizedSignature);
assert(methodIndex >= 0);
genericExec_method = this->metaObject()->method(methodIndex);
}
genericExec_method.invoke(this, connType, Q_ARG(std::function<void(void)>, func));
}
};
static inline
void execInMainThread_sync(std::function<void(void)> func) {
if(qApp->thread() == QThread::currentThread())
func();
else {
((App*) qApp)->invokeGenericExec(func, Qt::BlockingQueuedConnection);
}
}
static inline
void execInMainThread_async(std::function<void(void)> func) {
((App*) qApp)->invokeGenericExec(func, Qt::QueuedConnection);
}
It is certainly possible. Any solution will center on delivering an event that wraps the functor to a consumer object residing in the desired thread. We shall call this operation metacall posting. The particulars can be executed in several ways.
Qt 5.10 & up TL;DR
// invoke on the main thread
QMetaObject::invokeMethod(qApp, []{ ... });
// invoke on an object's thread
QMetaObject::invokeMethod(obj, []{ ... });
// invoke on a particular thread
QMetaObject::invokeMethod(QAbstractEventDispatcher::instance(thread),
[]{ ... });
TL;DR for functors
// https://github.com/KubaO/stackoverflown/tree/master/questions/metacall-21646467
// Qt 5.10 & up - it's all done
template <typename F>
static void postToObject(F &&fun, QObject *obj = qApp) {
QMetaObject::invokeMethod(obj, std::forward<F>(fun));
}
template <typename F>
static void postToThread(F && fun, QThread *thread = qApp->thread()) {
auto *obj = QAbstractEventDispatcher::instance(thread);
Q_ASSERT(obj);
QMetaObject::invokeMethod(obj, std::forward<F>(fun));
}
// Qt 5/4 - preferred, has least allocations
namespace detail {
template <typename F>
struct FEvent : public QEvent {
using Fun = typename std::decay<F>::type;
Fun fun;
FEvent(Fun && fun) : QEvent(QEvent::None), fun(std::move(fun)) {}
FEvent(const Fun & fun) : QEvent(QEvent::None), fun(fun) {}
~FEvent() { fun(); }
}; }
template <typename F>
static void postToObject(F && fun, QObject * obj = qApp) {
if (qobject_cast<QThread*>(obj))
qWarning() << "posting a call to a thread object - consider using postToThread";
QCoreApplication::postEvent(obj, new detail::FEvent<F>(std::forward<F>(fun)));
}
template <typename F>
static void postToThread(F && fun, QThread * thread = qApp->thread()) {
QObject * obj = QAbstractEventDispatcher::instance(thread);
Q_ASSERT(obj);
QCoreApplication::postEvent(obj, new detail::FEvent<F>(std::forward<F>(fun)));
}
// Qt 5 - alternative version
template <typename F>
static void postToObject2(F && fun, QObject * obj = qApp) {
if (qobject_cast<QThread*>(obj))
qWarning() << "posting a call to a thread object - consider using postToThread";
QObject src;
QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun),
Qt::QueuedConnection);
}
template <typename F>
static void postToThread2(F && fun, QThread * thread = qApp->thread()) {
QObject * obj = QAbstractEventDispatcher::instance(thread);
Q_ASSERT(obj);
QObject src;
QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun),
Qt::QueuedConnection);
}
void test1() {
QThread t;
QObject o;
o.moveToThread(&t);
// Execute in given object's thread
postToObject([&]{ o.setObjectName("hello"); }, &o);
// or
postToObject(std::bind(&QObject::setObjectName, &o, "hello"), &o);
// Execute in given thread
postToThread([]{ qDebug() << "hello from worker thread"; });
// Execute in the main thread
postToThread([]{ qDebug() << "hello from main thread"; });
}
TL;DR for methods/slots
// Qt 5/4
template <typename T, typename R>
static void postToObject(T * obj, R(T::* method)()) {
struct Event : public QEvent {
T * obj;
R(T::* method)();
Event(T * obj, R(T::*method)()):
QEvent(QEvent::None), obj(obj), method(method) {}
~Event() { (obj->*method)(); }
};
if (qobject_cast<QThread*>(obj))
qWarning() << "posting a call to a thread object - this may be a bug";
QCoreApplication::postEvent(obj, new Event(obj, method));
}
void test2() {
QThread t;
struct MyObject : QObject { void method() {} } obj;
obj.moveToThread(&t);
// Execute in obj's thread
postToObject(&obj, &MyObject::method);
}
TL;DR: What about a single shot timer?
All of the above methods work from threads that don't have an event loop. Due to QTBUG-66458, the handy appropriation of QTimer::singleShot needs an event loop in the source thread as well. Then postToObject becomes very simple, and you could possibly just use QTimer::singleShot directly, although it's an awkward name that hides the intent from those unfamiliar with this idiom. The indirection via a function named to better indicate the intent makes sense, even if you don't need the type check:
template <typename F>
static void postToObject(F && fun, QObject * obj = qApp) {
if (qobject_cast<QThread*>(obj))
qWarning() << "posting a call to a thread object - consider using postToThread";
QTimer::singleShot(0, obj, std::forward<F>(fun));
}
Common Code
Let's define our problem in terms of the following common code. The simplest solutions will post the event to either the application object, iff the target thread is the main thread, or to an event dispatcher for any other given thread. Since the event dispatcher will exist only after QThread::run has been entered, we indicate the requirement for the thread to be running by returning true from needsRunningThread.
#ifndef HAS_FUNCTORCALLCONSUMER
namespace FunctorCallConsumer {
bool needsRunningThread() { return true; }
QObject * forThread(QThread * thread) {
Q_ASSERT(thread);
QObject * target = thread == qApp->thread()
? static_cast<QObject*>(qApp) : QAbstractEventDispatcher::instance(thread);
Q_ASSERT_X(target, "postMetaCall", "the receiver thread must have an event loop");
return target;
}
}
#endif
The metacall posting functions, in their simplest form, require the functor call consumer to provide object for a given thread, and instantiate the functor call event. The implementation of the event is still ahead of us, and is the essential difference between various implementations.
The second overload takes a rvalue reference for the functor, potentially saving a copy operation on the functor. This is helpful if the continuation contains data that is expensive to copy.
#ifndef HAS_POSTMETACALL
void postMetaCall(QThread * thread, const std::function<void()> & fun) {
auto receiver = FunctorCallConsumer::forThread(thread);
QCoreApplication::postEvent(receiver, new FunctorCallEvent(fun, receiver));
}
void postMetaCall(QThread * thread, std::function<void()> && fun) {
auto receiver = FunctorCallConsumer::forThread(thread);
QCoreApplication::postEvent(receiver,
new FunctorCallEvent(std::move(fun), receiver));
}
#endif
For demonstration purposes, the worker thread first posts a metacall to the main thread, and then defers to QThread::run() to start an event loop to listen for possible metacalls from other threads. A mutex is used to allow the thread user to wait in a simple fashion for the thread to start, if necessitated by the consumer's implementation. Such wait is necessary for the default event consumer given above.
class Worker : public QThread {
QMutex m_started;
void run() {
m_started.unlock();
postMetaCall(qApp->thread(), []{
qDebug() << "worker functor executes in thread" << QThread::currentThread();
});
QThread::run();
}
public:
Worker(QObject * parent = 0) : QThread(parent) { m_started.lock(); }
~Worker() { quit(); wait(); }
void waitForStart() { m_started.lock(); m_started.unlock(); }
};
Finally, we start the above worker thread that posts a metacall to the main (application) thread, and the application thread posts a metacall to the worker thread.
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
a.thread()->setObjectName("main");
Worker worker;
worker.setObjectName("worker");
qDebug() << "worker thread:" << &worker;
qDebug() << "main thread:" << QThread::currentThread();
if (FunctorCallConsumer::needsRunningThread()) {
worker.start();
worker.waitForStart();
}
postMetaCall(&worker, []{ qDebug() << "main functor executes in thread" << QThread::currentThread(); });
if (!FunctorCallConsumer::needsRunningThread()) worker.start();
QMetaObject::invokeMethod(&a, "quit", Qt::QueuedConnection);
return a.exec();
}
The output will look approximately as follows in all implementations. The functors cross the threads: the one created in the main thread is executed in the worker thread, and vice-versa.
worker thread: QThread(0x7fff5692fc20, name = "worker")
main thread: QThread(0x7f86abc02f00, name = "main")
main functor executes in thread QThread(0x7fff5692fc20, name = "worker")
worker functor executes in thread QThread(0x7f86abc02f00, name = "main")
Qt 5 Solution Using a Temporary Object as The Signal Source
The simplest approach for Qt 5 is to use a temporary QObject as a signal source, and connect the functor to its destroyed(QObject*) signal. When postMetaCall returns, the signalSource gets destructed, emits its destroyed signal, and posts the metacall to the proxy object.
This is perhaps the most concise and straightforward implementation in the C++11 style. The signalSource object is used in the C++11 RAII fashion for the side effects of its destruction. The phrase "side effects" has a meaning within C++11's semantics and should not be interpreted to mean "unreliable" or "undesirable" - it's anything but. QObject's contract with us is to emit destroyed sometime during the execution of its destructor. We're more than welcome to use that fact.
#include <QtCore>
#include <functional>
namespace FunctorCallConsumer { QObject * forThread(QThread*); }
#define HAS_POSTMETACALL
void postMetaCall(QThread * thread, const std::function<void()> & fun) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed,
FunctorCallConsumer::forThread(thread), [=](QObject*){ fun(); });
}
#ifdef __cpp_init_captures
void postMetaCall(QThread * thread, std::function<void()> && fun) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed,
FunctorCallConsumer::forThread(thread), [fun(std::move(fun))](QObject*){ fun(); });
}
#endif
// Common Code follows here
If we only intend to post to the main thread, the code becomes almost trivial:
void postToMainThread(const std::function<void()> & fun) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed, qApp, [=](QObject*){
fun();
});
}
#ifdef __cpp_init_captures
void postToMainThread(std::function<void()> && fun) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed, qApp, [fun(std::move(fun))](QObject*){
fun();
});
}
#endif
Qt 4/5 Solution Using QEvent Destructor
The same approach can be applied to QEvent directly. The event's virtual destructor can call the functor. The events are deleted right after they are delivered by the consumer object's thread's event dispatcher, so they always execute in the right thread. This will not change in Qt 4/5.
#include <QtCore>
#include <functional>
class FunctorCallEvent : public QEvent {
std::function<void()> m_fun;
QThread * m_thread;
public:
FunctorCallEvent(const std::function<void()> & fun, QObject * receiver) :
QEvent(QEvent::None), m_fun(fun), m_thread(receiver->thread()) {}
FunctorCallEvent(std::function<void()> && fun, QObject * receiver) :
QEvent(QEvent::None), m_fun(std::move(fun)), m_thread(receiver->thread()) { qDebug() << "move semantics"; }
~FunctorCallEvent() {
if (QThread::currentThread() == m_thread)
m_fun();
else
qWarning() << "Dropping a functor call destined for thread" << m_thread;
}
};
// Common Code follows here
To post to main thread only, things become even simpler:
class FunctorCallEvent : public QEvent {
std::function<void()> m_fun;
public:
FunctorCallEvent(const std::function<void()> & fun) :
QEvent(QEvent::None), m_fun(fun) {}
FunctorCallEvent(std::function<void()> && fun, QObject * receiver) :
QEvent(QEvent::None), m_fun(std::move(fun)) {}
~FunctorCallEvent() {
m_fun();
}
};
void postToMainThread(const std::function<void()> & fun) {
QCoreApplication::postEvent(qApp, new FunctorCallEvent(fun);
}
void postToMainThread(std::function<void()> && fun) {
QCoreApplication::postEvent(qApp, new FunctorCallEvent(std::move(fun)));
}
Qt 5 Solution Using the Private QMetaCallEvent
The functor can be wrapped in the Qt 5 slot object payload of the QMetaCallEvent. The functor will be invoked by QObject::event, and thus can be posted to any object in the target thread. This solution uses the private implementation details of Qt 5.
#include <QtCore>
#include <private/qobject_p.h>
#include <functional>
class FunctorCallEvent : public QMetaCallEvent {
public:
template <typename Functor>
FunctorCallEvent(Functor && fun, QObject * receiver) :
QMetaCallEvent(new QtPrivate::QFunctorSlotObject<Functor, 0, typename QtPrivate::List_Left<void, 0>::Value, void>
(std::forward<Functor>(fun)), receiver, 0, 0, 0, (void**)malloc(sizeof(void*))) {}
// Metacalls with slot objects require an argument array for the return type, even if it's void.
};
// Common Code follows here
Qt 4/5 Solution Using a Custom Event and Consumer
We reimplement the event() method of the object, and have it call the functor. This calls for an explicit event consumer object in each thread that the functors are posted to. The object is cleaned up when its thread is finished, or, for the main thread, when the application instance is destructed. It works on both Qt 4 and Qt 5. The use of rvalue references avoids copying of the temporary functor.
#include <QtCore>
#include <functional>
class FunctorCallEvent : public QEvent {
std::function<void()> m_fun;
public:
FunctorCallEvent(const std::function<void()> & fun, QObject *) :
QEvent(QEvent::None), m_fun(fun) {}
FunctorCallEvent(std::function<void()> && fun, QObject *) :
QEvent(QEvent::None), m_fun(std::move(fun)) { qDebug() << "move semantics"; }
void call() { m_fun(); }
};
#define HAS_FUNCTORCALLCONSUMER
class FunctorCallConsumer : public QObject {
typedef QMap<QThread*, FunctorCallConsumer*> Map;
static QObject * m_appThreadObject;
static QMutex m_threadObjectMutex;
static Map m_threadObjects;
bool event(QEvent * ev) {
if (!dynamic_cast<FunctorCallEvent*>(ev)) return QObject::event(ev);
static_cast<FunctorCallEvent*>(ev)->call();
return true;
}
FunctorCallConsumer() {}
~FunctorCallConsumer() {
qDebug() << "consumer done for thread" << thread();
Q_ASSERT(thread());
QMutexLocker lock(&m_threadObjectMutex);
m_threadObjects.remove(thread());
}
static void deleteAppThreadObject() {
delete m_appThreadObject;
m_appThreadObject = nullptr;
}
public:
static bool needsRunningThread() { return false; }
static FunctorCallConsumer * forThread(QThread * thread) {
QMutexLocker lock(&m_threadObjectMutex);
Map map = m_threadObjects;
lock.unlock();
Map::const_iterator it = map.find(thread);
if (it != map.end()) return *it;
FunctorCallConsumer * consumer = new FunctorCallConsumer;
consumer->moveToThread(thread);
if (thread != qApp->thread())
QObject::connect(thread, SIGNAL(finished()), consumer, SLOT(deleteLater()));
lock.relock();
it = m_threadObjects.find(thread);
if (it == m_threadObjects.end()) {
if (thread == qApp->thread()) {
Q_ASSERT(! m_appThreadObject);
m_appThreadObject = consumer;
qAddPostRoutine(&deleteAppThreadObject);
}
m_threadObjects.insert(thread, consumer);
return consumer;
} else {
delete consumer;
return *it;
}
}
};
QObject * FunctorCallConsumer::m_appThreadObject = nullptr;
QMutex FunctorCallConsumer::m_threadObjectMutex;
FunctorCallConsumer::Map FunctorCallConsumer::m_threadObjects;
// Common Code follows here
There are one new approach that is the easiest I think.
It`s from Qt 5.4. Link to documentation
void QTimer::singleShot(int msec, const QObject *context, Functor functor)
Example:
QTimer::singleShot(0, qApp, []()
{
qDebug() << "hi from event loop";
});
lambda will be executed in qApp thread(main thread). You could replace context with any QObject you want.
Updated
QTimer needs event loop to work. For Threads with no qt event loop(std::thread) we could create one. Code to run lambda in std::thread.
QEventLoop loop;
Q_UNUSED(loop)
QTimer::singleShot(0, qApp, []()
{
qDebug() << "singleShot from std thread";
});
Full example
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>
#include <thread>
#include <QThread>
#include <QEventLoop>
#include <QThread>
using std::thread;
class TestObj
:public QObject
{
// Used new connect syntax no need for Q_OBJECT define
// you SHOULD use it. I used just to upload one file
//Q_OBJECT
public slots:
void doWork()
{
qDebug() << "QThread id" << QThread::currentThreadId();
QTimer::singleShot(0, qApp, []()
{
qDebug() << "singleShot from QThread" << QThread::currentThreadId();
});
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "main thread id" << QThread::currentThreadId();
thread testThread([]()
{
QEventLoop loop;
Q_UNUSED(loop)
qDebug() << "std::thread id" << QThread::currentThreadId();
QTimer::singleShot(0, qApp, []()
{
qDebug() << "singleShot from std thread" << QThread::currentThreadId();
});
qDebug() << "std::thread finished";
});
testThread.detach();
QThread testQThread;
TestObj testObj;
testObj.moveToThread(&testQThread);
QObject::connect(&testQThread, &QThread::started, &testObj, &TestObj::doWork);
testQThread.start();
return a.exec();
}
May something like this be any useful?
template <typename Func>
inline static void MyRunLater(Func func) {
QTimer *t = new QTimer();
t->moveToThread(qApp->thread());
t->setSingleShot(true);
QObject::connect(t, &QTimer::timeout, [=]() {
func();
t->deleteLater();
});
QMetaObject::invokeMethod(t, "start", Qt::QueuedConnection, Q_ARG(int, 0));
}
This piece of code will make your lambda run on the main thread event loop as soon as it is possible.
No args support, this is a very basic code.
NOTE: I didn't test it properly.
Others have exelent answers. here is my suggest. instead of doing something like this:-
QMetaObject::invokeMethod(socketManager,"newSocket",
Qt::QueuedConnection,
Q_ARG(QString, host),
Q_ARG(quint16, port.toUShort()),
Q_ARG(QString, username),
Q_ARG(QString, passhash)
);
do something like this which is more nice:-
QMetaObject::invokeMethod(socketManager,[=](){
socketManager->newSocket(host,port.toUShort(),username,passhash);
},Qt::QueuedConnection);
I have absolutely no idea what your talking about, but I'm going to try to answer it any way.
Lets say your have a class with a slot fucntion
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass() {}
public slots:
void MySlot() { qDebug() << "RAWR";
};
So no if you want to run this synchronously in the main thread you can call that function directly. In order to connect a signal you need to create an object and connect a signal to the slot.
class MySignalClass : public QObject
{
Q_OBJECT
public:
MySignalClass() {}
signalSomthign() { emit someAwesomeSignal; }
public signals:
void someAwesomeSignal();
};
And somwhere in the main thread you do something like
MyClass slotClass;
MySignalClass signalClass;
qobject::connect(&signalClass, SIGNAL(someAwesomeSignal), &slotClass(), SLOT(MySlot)));
So now if something you can connect multiple signals to that slot object, but realisticly the code I provided won't run any different than a normal function call. You'll be able to see that with a stack trace. If you add the flag qobject::queuedConneciton to the connect then it will que the slot call in the event loop.
You can easily thread a signal as well, but this will automatically be a queuedConnection
MyClass slotClass;
MySignalClass signalClass;
QThread someThread;
slotClass.moveToThread(&someThread);
qobject::connect(&signalClass, SIGNAL(someAwesomeSignal), &slotClass(), SLOT(MySlot)));
Now you'll have a threaded signal basically. If your signal is going to be threaded then all you have to do is switch to signalClass.moveToThread(&someThread), when the signal is emitted signalClass will be run in the main thread.
If you don't want an object to be called, I'm not sure, lamdas might work. I've used them before but Ithink they still need to be wrapped up in a class.
qobject::connect(&signalClass, &slotClass::MySlot, [=]() { /* whatever */ });
Although I'm pretty sure with Qt5 you can even go as far as creating a slot in line within a connect. But once your using lambdas I have no idea how threads work with them. As far as I know you need an object to sit in a thread basically to force calling the slot from the main thread.

Execute slots inside a QThreadPool

I have a class that should run in a thread and needs an event loop for the slots, currently I run it nicely with moveToThread(), but I'd like to use QThreadPool and I have encountered a problem.
When run with QThreadPool the run() method of my runnable is called from a pooled thread (I check this with QThread::currentThread()), but my slots aren't running in the pooled thread, so I think the object isn't moved to a thread in the pool.
I think this because I know the slots are run in the receiver's thread, which is exactly the (correct) behaviour I get when using the moveToThread() method and a QThread.
How do I get my QRunnable (Foo in the example below) to be run entirely in the pooled threads?
Or is it something I'm doing wrong or understood wrong?
The following POC demonstrates the problem:
foo.h
#ifndef FOO_H
#define FOO_H
#include <QObject>
#include <QRunnable>
#include <QEventLoop>
class Foo : public QObject, public QRunnable
{
Q_OBJECT
public:
explicit Foo(int data, QObject *parent = 0);
void run();
signals:
void startWorking();
public slots:
void doWork();
private:
QEventLoop eventLoop;
int data;
};
#endif // FOO_H
foo.cpp
#include "foo.h"
#include <QThread>
#include <QDebug>
Foo::Foo(int d, QObject *parent) :
QObject(parent), eventLoop(this), data(d)
{
}
void Foo::run()
{
qDebug() << "run() in: " << QThread::currentThread();
connect(this, SIGNAL(startWorking()), this, SLOT(doWork()));
emit startWorking();
eventLoop.exec();
}
void Foo::doWork()
{
qDebug() << "doWork() in: " << QThread::currentThread();
}
main.cpp
#include <QCoreApplication>
#include <QThreadPool>
#include "foo.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Foo *foo = new Foo(42);
QThreadPool::globalInstance()->start(foo);
return a.exec();
}
Please note, however, that in my real code the signal won't be emitted right away, because it will be after I receive some data on the network.
PS: The POC can also be found here.
Maybe you could split your logic in class Foo into two:
the hoster QRunnable with a QEventLoop, and a worker QObject, which you create on the worker thread in run() before calling QEventLoop::exec method. Then you forward all the signals to the worker object.
So now your slots will be called on the pooled thread.
However, QThreadPool is designed for executing lots of short tasks without creating too many simultaneous threads. Some tasks are enqueued and are waiting for others to finish. If this is not your intention, you might want to go back to good old QThread and use it instead.
You can support both modes but it will require some coordination from the outside. My strategy is to emit a signal from inside QRunnable::run passing the current thread. When you plan to use it in a thread pool, use a Qt::BlockingQueuedConnection on this signal and do your moveToThread there. Otherwise, move it to the QThread and emit a signal to start working as usual.
TaskRunner.h
#pragma once
#include <QObject>
#include <QRunnable>
#include <QThread>
class TaskRunner : public QObject, public QRunnable
{
Q_OBJECT
public:
TaskRunner(int data, QObject* parent = nullptr);
void run() override;
Q_SIGNALS:
void start();
void starting(QThread*);
void stop();
private:
int data;
};
TaskRunner.cpp
#include "TaskRunner.h"
#include <QEventLoop>
#include <stdexcept>
TaskRunner::TaskRunner(int data, QObject* parent)
: QObject(parent), data(data)
{
// start should call run in the associated thread
QObject::connect(this, &TaskRunner::start, this, &TaskRunner::run);
}
void TaskRunner::run()
{
// in a thread pool, give a chance to move us to the current thread
Q_EMIT starting(QThread::currentThread());
if (thread() != QThread::currentThread())
throw std::logic_error("Not associated with proper thread.");
QEventLoop loop;
QObject::connect(this, &TaskRunner::stop, &loop, &QEventLoop::quit);
// other logic here perhaps
loop.exec();
}
main.cpp
#include <QCoreApplication>
#include <QThreadPool>
#include "TaskRunner.h"
// comment to switch
#define USE_QTHREAD
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
auto runner = new TaskRunner(42);
#ifdef USE_QTHREAD
// option 1: on a QThread
auto thread = new QThread(&a);
runner->moveToThread(thread);
QObject::connect(thread, &QThread::finished, runner, &QObject::deleteLater);
Q_EMIT runner->start();
// stop condition not shown
#else
// option 2: in a thread pool
QObject::connect(
runner, &TaskRunner::starting,
runner, &QObject::moveToThread,
Qt::BlockingQueuedConnection);
QThreadPool::globalInstance()->start(runner);
// stop condition not shown
#endif
return a.exec();
}
Since the your connect call
connect(this, SIGNAL(startWorking()), this, SLOT(doWork()));
used the default parameter for connection type, it will be a Qt::Autoconnection.
The signal is emitted from the pooled thread, and the slot still belongs to foo, which has a thread affinity to the main thread. The autoconnection will decide to put the slot in the event queue of the main thread.
There are two ways you can fix this:
1.
connect(this, SIGNAL(startWorking()), this, SLOT(doWork()), Qt::DirectConnection);
and remove the eventloop.exec();
2.
in the run method, move the foo object to the current thread before connecting the signal and slot.

QtConcurrent::run emit signal

I would like to emit a signal in Qt, from a function that I called with QtConcurrent::run
Is this possible? It seems like my slot never gets called. All of the signals, slots, and functions are part of the same class object. I have tried making the connection in the Master thread, and in the slave thread. I dont really care if the signal and slot are in the same thread or not, I just want to get it to happen.
Thanks
The below works just fine in Qt 4.8.7. The signal is emitted from the worker thread, and consumed in the main thread. We assert that the slot runs in the main thread, and the functor runs in the worker thread.
// https://github.com/KubaO/stackoverflown/tree/master/questions/concurrent-emit-qt4-7114421
#include <QtCore>
class Helper : public QObject {
Q_OBJECT
public:
int n = 0;
Q_SLOT void increment() {
Q_ASSERT(QThread::currentThread() == qApp->thread());
n++;
}
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
Helper helper;
Q_ASSERT(helper.n == 0);
QtConcurrent::run([&]{
Q_ASSERT(QThread::currentThread() != qApp->thread());
QObject src;
QObject::connect(&src, SIGNAL(destroyed(QObject*)), &helper, SLOT(increment()));
QObject::connect(&src, SIGNAL(destroyed(QObject*)), &app, SLOT(quit()));
});
app.exec();
Q_ASSERT(helper.n == 1);
}
#include "main.moc"
In Qt 5, you don't need the helper class to demonstrate that it works:
#include <QtConcurrent>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
int n = 0;
Q_ASSERT(n == 0);
QtConcurrent::run([&]{
Q_ASSERT(QThread::currentThread() != qApp->thread());
QObject src;
QObject::connect(&src, &QObject::destroyed, &app, [&]{
Q_ASSERT(QThread::currentThread() == qApp->thread());
n ++;
qApp->quit();
});
});
app.exec();
Q_ASSERT(n == 1);
}
You can use a Qt::QueuedConnection for that connection (pass it to the connect call which establishes the connection), since the signal will always be emitted from a different thread than the receiver objects thread.
An Qt::AutoConnection will also do the same thing and add the signal to the event queue of the thread of the receiving object.
If the receiving thread is blocked, and thus never reenters the event queue, the signal cannot be received by the slot of the receiving object.
You really should use QFuture and QFutureWatcher with QtConcurrent::run().
yes it is possible.
just look little example:
in this example we want implement multithread. longProcess function go to thread pool and process in thread pool and after that answer of long process function back to main thread.
Test.h
Class Test: public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent = nullptr);
void resultAvailable();
static void doLongProcess(Test *test);
signals:
void finishedProcess(const QString &massage);
public slots:
void captureSignal(const QString &message);
};
Test.cpp
void Test::resultAvailable()
{
QtConcurrent::run(&ContactsModelManager::doLongProcess, this);
connect(this , &Test::finishedProcess,
this , &Test::captureSignal);
}
//attention!! doLongProcess is static fnuction
void Test::doLongProcess(Test *test)
{
//this process is very long
test->longProcess();
}
void Test::longProcess()
{
//do your process
//at the end emit your signal
emit finishedProcess("finished process in another thread");
}
void Test::captureSignal(const QString &message)
{
Qdebug() << "message is: " << message;
}