Last active
April 13, 2017 16:24
-
-
Save micjabbour/b8b3cfd1b566a041b8ad279a139e8362 to your computer and use it in GitHub Desktop.
Some useful QThread utilities, that can be used to call functors in other threads (and possibly grab their return value)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "qthreadutils.h" | |
#include <QtCore> | |
//the following file shows an example usage for CallByWorker | |
//a thread that can be destroyed at any time | |
//see http://stackoverflow.com/a/25230470 | |
class SafeThread : public QThread{ | |
using QThread::run; | |
public: | |
explicit SafeThread(QObject* parent= nullptr):QThread(parent){} | |
~SafeThread(){ quit(); wait(); } | |
}; | |
int main(int argc, char *argv[]) | |
{ | |
QCoreApplication a(argc, argv); | |
QObject worker; | |
SafeThread thread; | |
thread.start(); | |
worker.moveToThread(&thread); | |
auto workerThread = CallByWorker(&worker, []{ return QThread::currentThread(); }); | |
Q_ASSERT(workerThread == worker.thread()); //lambda is executed in the worker's thread | |
qDebug() << "main thread:\t" << QThread::currentThread(); | |
qDebug() << "worker thread:\t" << workerThread; | |
QTimer::singleShot(1000, &a, &QCoreApplication::quit); | |
return a.exec(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef QTHREADUTILS_H | |
#define QTHREADUTILS_H | |
#include <QObject> | |
#include <QThread> | |
//FunctorTraits is used to get the return type of a lambda expression | |
//see http://stackoverflow.com/a/7943765 | |
template <typename T> | |
struct FunctorTraits : public FunctorTraits<decltype(&T::operator())> {}; | |
template <typename ClassType, typename ReturnType, typename... Args> | |
struct FunctorTraits< ReturnType (ClassType::*)(Args...) const> { | |
typedef ReturnType return_t; | |
}; | |
//The function queues a functor to get executed in a specified worker's thread | |
//the connectionType argument determines if the function needs to wait for the functor to finish (By default it does NOT) | |
template <typename Func> | |
void PostToWorker(QObject* worker, Func&& f, Qt::ConnectionType connectionType = Qt::QueuedConnection) { | |
//see http://stackoverflow.com/a/21653558 | |
QObject temporaryObject; | |
QObject::connect(&temporaryObject, &QObject::destroyed, | |
worker, std::forward<Func>(f), connectionType); | |
} | |
//The function executes a functor in a specified worker's thread | |
//it waits for the functor to finish, and returns its result to the caller in the current thread | |
template <typename Func> //for functors returning non-void | |
typename std::enable_if<!std::is_void<typename FunctorTraits<Func>::return_t>::value, typename FunctorTraits<Func>::return_t>::type | |
CallByWorker(QObject* worker, Func&& f) { | |
Qt::ConnectionType blockingConnectionType = QThread::currentThread() == worker->thread() ? | |
Qt::DirectConnection : Qt::BlockingQueuedConnection; | |
typename FunctorTraits<Func>::return_t returnValue; | |
auto myFunctor = [&]{ | |
returnValue= std::forward<Func>(f)(); | |
}; | |
PostToWorker(worker, myFunctor, blockingConnectionType); | |
return returnValue; | |
} | |
//if the functor returns void, no need to use a custom functor like above | |
template <typename Func> //for functors returning void | |
typename std::enable_if<std::is_void<typename FunctorTraits<Func>::return_t>::value, void>::type | |
CallByWorker(QObject* worker, Func&& f) { | |
Qt::ConnectionType blockingConnectionType = QThread::currentThread() == worker->thread() ? | |
Qt::DirectConnection : Qt::BlockingQueuedConnection; | |
PostToWorker(worker, std::forward<Func>(f), blockingConnectionType); | |
} | |
#endif // QTHREADUTILS_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment