In C++ Builder, how to execute a function inside a `TThread`? - multithreading

I created a TThread using the File > New > Other > Thread Object menu. It gave me some boilerplate code, like this:
//---------------------------------------------------------------------------
#include <System.hpp>
#pragma hdrstop
#include "Unit2.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(&UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall MyThreadClass::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }
//---------------------------------------------------------------------------
__fastcall MyThreadClass::MyThreadClass(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall MyThreadClass::Execute()
{
NameThreadForDebugging(System::String(L"MyThread"));
//---- Place thread code here ----
ShowMessage("Hello World!");
}
//---------------------------------------------------------------------------
header
//---------------------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
//---------------------------------------------------------------------------
class MyThreadClass : public TThread
{
protected:
void __fastcall Execute();
public:
__fastcall MyThreadClass(bool CreateSuspended);
};
//---------------------------------------------------------------------------
#endif
I added the line you can see, ShowMessage("Hello World!"), and ran the program, but nothing happens besides my form being displayed.
How do I execute the code inside my thread function?

I had to replace the ShowMessage("Hello World!") line with this:
Synchronize([](){ ShowMessage("Hello World!"); });
And create the thread with this:
MyThreadClass* myThread = new MyThreadClass(false); // false == don't create suspended

Related

How to share data between a TThread in a DLL and the main thread?

I'm writing a DLL in C++Builder XE6, that creates a separate thread (derived from TThread) to retrieve JSON data from a REST server every X seconds (using TIdHTTP), and parse the JSON data.
The thread fills a simple struct (no dynamically allocated data) with the parsed JSON data in the Execute() method of the thread:
typedef struct
{
char MyString[40 + 1];
double MyDouble;
bool MyBool;
} TMyStruct;
The thread should store the struct in a list, for example a std::vector:
#include <vector>
std::vector<TMyStruct> MyList;
The thread will add a TMyStruct to the list:
TMyStruct Data;
...
MyList.push_back(Data);
The list will be guarded by a TCriticalSection to prevent data corruption.
The DLL exports a function to retrieve a TMyStruct from MyList.
bool __declspec(dllexport) __stdcall GetMyStruct (int Index, TMyStruct* Data)
{
...
}
Only thing is, I don't know where to put MyList...
If I make MyList a global variable, it is located in the main thread's memory and GetMyStruct() can access it directly. How does the thread access MyList?
If I make MyList a member of the TThread-derived class, it is located in the thread's memory and the thread can access it directly. How does GetMyStruct() access MyList?
What is the best/prefered/common way to store MyList and access it in a different thread?
If I make MyList a global variable, it is located in the main thread's memory and GetMyStruct() can access it directly. How does the thread access MyList?
The exact same way. All threads in a process can freely access global variables within that process. For example:
#include <vector>
#include <System.SyncObjs.hpp>
typedef struct
{
char MyString[40 + 1];
double MyDouble;
bool MyBool;
} TMyStruct;
std::vector<TMyStruct> MyList;
TCriticalSection *Lock = NULL; // why not std::mutex instead?
class TMyThread : public TThread
{
...
};
TMyThread *Thread = NULL;
...
void __fastcall TMyThread::Execute()
{
TMyStruct Data;
...
Lock->Enter();
try {
MyList.push_back(Data);
}
__finally {
Lock->Leave();
}
...
}
...
void __declspec(dllexport) __stdcall StartThread ()
{
Lock = new TCriticalSection;
Thread = new TMyThread;
}
void __declspec(dllexport) __stdcall StopThread ()
{
if (Thread) {
Thread->Terminate();
Thread->WaitFor();
delete Thread;
Thread = NULL;
}
if (Lock) {
delete Lock;
Lock = NULL;
}
}
bool __declspec(dllexport) __stdcall GetMyStruct (int Index, TMyStruct* Data)
{
if (!(Lock && Thread)) return false;
Lock->Enter();
try {
*Data = MyList[Index];
}
__finally {
Lock->Leave();
}
return true;
}
If I make MyList a member of the TThread-derived class, it is located in the thread's memory and the thread can access it directly. How does GetMyStruct() access MyList?
By accessing it via a pointer to the thread object. For example:
#include <vector>
#include <System.SyncObjs.hpp>
typedef struct
{
char MyString[40 + 1];
double MyDouble;
bool MyBool;
} TMyStruct;
class TMyThread : public TThread
{
protected:
void __fastcall Execute();
public:
__fastcall TMyThread();
__fastcall ~TMyThread();
std::vector<TMyStruct> MyList;
TCriticalSection *Lock;
};
TMyThread *Thread = NULL;
...
__fastcall TMyThread::TMyThread()
: TThread(false)
{
Lock = new TCriticalSection;
}
__fastcall TMyThread::~TMyThread()
{
delete Lock;
}
void __fastcall TMyThread::Execute()
{
TMyStruct Data;
...
Lock->Enter();
try {
MyList.push_back(Data);
}
__finally {
Lock->Leave();
}
...
}
void __declspec(dllexport) __stdcall StartThread ()
{
Thread = new TMyThread;
}
void __declspec(dllexport) __stdcall StopThread ()
{
if (Thread) {
Thread->Terminate();
Thread->WaitFor();
delete Thread;
Thread = NULL;
}
}
bool __declspec(dllexport) __stdcall GetMyStruct (int Index, TMyStruct* Data)
{
if (!Thread) return false;
Thread->Lock->Enter();
try {
*Data = Thread->MyList[Index];
}
__finally {
Thread->Lock->Leave();
}
return true;
}
What is the best/prefered/common way to store MyList and access it in a different thread?
That is entirely up to you to decide, based on your particular needs and project design.

Timers cannot be stopped from another thread Qt

I am working on Qt application. There I am using two threads, one for the GUI and one for do the processing.
I have worker class which has QTimer as member class.
.h file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include <QThread>
class Worker : public QObject
{
Q_OBJECT
public:
Worker();
QTimer t;
public slots:
void process();
void startWorker();
};
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
QThread workerThread;
Worker wt;
};
#endif // MAINWINDOW_H
cpp file
#include "mainwindow.h"
#include <QDebug>
#include <iostream>
Worker::Worker() : t(this)
{
connect(&t, SIGNAL(timeout()), this, SLOT(process()));
}
void Worker::process()
{
std::cout << "triggering timer" << std::endl;
}
void Worker::startWorker()
{
t.start(1000);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
wt.moveToThread(&workerThread);
qDebug() << "worker thread " << wt.thread();
qDebug() << "timer thread " << wt.t.thread();
connect(&workerThread, SIGNAL(started()), &wt, SLOT(startWorker()));
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
workerThread.start();
}
MainWindow::~MainWindow()
{
workerThread.quit();
workerThread.wait();
}
I can start the thread with no error. However when I close the application I am getting warning message.
QObject::killTimer: Timers cannot be stopped from another thread
QObject::~QObject: Timers cannot be stopped from another thread
If QTimer is child of worker class and it has been moved to thread why Qt is complaining about stopping it from different thread?
Note: I have added logs to print thread id and it outputs same value in both cases:
worker thread QThread(0x72fdf0)
timer thread QThread(0x72fdf0)
Can someone please explain? I do not understand what it's happening here
Thanks in advance
I finally was able to fix the error by:
Converting QTimer to pointer
Adding slot stopWorker as suggested by #Amfasis
In that slot not only stop QTimer but also delete it
Thanks all
You should stop the timer before QObject deletes it itself
in .h file, add the destructor:
class Worker : public QObject
{
Q_OBJECT
public:
Worker();
~Worker();
private:
QTimer t;
public slots:
void process();
void startWorker();
void stopWorker(); //this line was added
};
in .cpp file, add:
Worker::stopWorker()
{
t.stop();
}
and in constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
...
connect(&workerThread, &QThread::finished, &wt, &Worker::stopWorker); //add this line!
...
}
You should new your timer in your task object slot, not in the task construtor. Stop the timer when your task object is deleted.
My task object header: Worker.h
#pragma once
#include <QObject>
class QTimer;
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
~Worker();
public slots:
void WorkerTaskStartSlot(void);
void TaskFinished(void);
private slots:
void TimerOutToDoSomethingSlot(void);
signals:
void WorkertResultSig(void);
private:
QTimer *m_pTimer = nullptr;
};
Worker.cpp:
#include "Worker.h"
#include <QDebug>
#include <QThread>
#include <QTimer>
Worker::Worker(QObject *parent) : QObject(parent)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
Worker::~Worker()
{
TaskFinished();
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
void Worker::WorkerTaskStartSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
emit WorkertResultSig();
m_pTimer = new QTimer(this);
connect(m_pTimer,&QTimer::timeout,this,&Worker::TimerOutToDoSomethingSlot);
m_pTimer->start(1000);
}
void Worker::TaskFinished(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
if(m_pTimer)
{
if(m_pTimer->isActive())
{
m_pTimer->stop();
qDebug()<<__FUNCTION__<<"stop timer"<< QThread::currentThreadId();
}
delete m_pTimer;
m_pTimer = nullptr;
}
}
void Worker::TimerOutToDoSomethingSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
The controller header: MainWindow.h
#pragma once
#include <QMainWindow>
class QPushButton;
class QWidget;
class Worker;
class QThread;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void InitCtrl(void);
private slots:
void StartTaskBtnSlot(const bool &checked);
void WorkertResultSlot(void);
private:
QPushButton *m_pStartTaskBtn = nullptr;
QWidget *m_pCenterWidget = nullptr;
Worker *m_pWorker = nullptr;
QThread *m_pWorkerThread = nullptr;
};
MainWindow.cpp
#include "MainWindow.h"
#include <QVBoxLayout>
#include <QPushButton>
#include <QWidget>
#include <QDebug>
#include <QThread>
#include "Worker.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
InitCtrl();
qDebug()<<__FUNCTION__<<"mainwindow thread id"<< QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
}
void MainWindow::InitCtrl(void)
{
m_pCenterWidget = new QWidget(this);
m_pStartTaskBtn = new QPushButton(QStringLiteral("Start"),this);
QVBoxLayout *pvertlayout = new QVBoxLayout();
pvertlayout->addWidget(m_pStartTaskBtn);
m_pCenterWidget->setLayout(pvertlayout);
setCentralWidget(m_pCenterWidget);
m_pStartTaskBtn->setCheckable(true);
connect(m_pStartTaskBtn,&QPushButton::clicked,this,&MainWindow::StartTaskBtnSlot);
}
void MainWindow::StartTaskBtnSlot(const bool &checked)
{
if(checked)
{
m_pStartTaskBtn->setText(QStringLiteral("Close"));
m_pWorkerThread = new QThread();
m_pWorker = new Worker();
// move the task object to the thread BEFORE connecting any signal/slots
m_pWorker->moveToThread(m_pWorkerThread);
connect(m_pWorkerThread, SIGNAL(started()), m_pWorker, SLOT(WorkerTaskStartSlot()));
connect(m_pWorker, SIGNAL(WorkertResultSig()), this, SLOT(WorkertResultSlot()));
// automatically delete thread and task object when work is done:
connect(m_pWorkerThread, SIGNAL(finished()), m_pWorker, SLOT(deleteLater()));
connect(m_pWorkerThread, SIGNAL(finished()), m_pWorkerThread, SLOT(deleteLater()));
m_pWorkerThread->start();
}
else
{
m_pStartTaskBtn->setText(QStringLiteral("Start"));
m_pWorkerThread->quit();
m_pWorkerThread->wait();
}
}
void MainWindow::WorkertResultSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<<QThread::currentThreadId();
}
Finally, it will output result like this:
MainWindow::MainWindow mainwindow thread id 0x2bf0
Worker::Worker threadid 0x2bf0
Worker::WorkerTaskStartSlot threadid 0x4af0
MainWindow::WorkertResultSlot threadid 0x2bf0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TaskFinished threadid 0x4af0
Worker::TaskFinished stop timer 0x4af0
Worker::~Worker threadid 0x4af0

Qt - Close QThreads that are blocked by system-level calls

I have a thread which blocks until data is received from a system resources such as a USB device. I chose this model because the amount of data may vary, and data may be received at any time. Upon exiting the application, I get the message “QThread: Destroyed while thread is still running”. How should I go about closing these threads?
I’ve looked at other problems/solutions such as:
http://www.qtcentre.org/threads/14429-Loop-inside-Qthread-causes-quot-QThread-Destroyed-while-thread-is-still-running-quot
http://www.qtcentre.org/threads/6211-QThread-Destroyed-while-thread-is-still-running
The first solution involves using a flag (included in my code) however my thread will never reach the flag check.
The second solution uses QWaitCondition but seem to be along the same lines as the first.
I’ve included a stripped down version of the code below. The system calls WaitForSingleObject() is a substitute for what I actually use (GetOverlappedResult()).
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QObject>
#include <QThread>
#include <QReadWriteLock>
#include <QDebug>
#ifdef Q_OS_WIN
#include <windows.h>
#endif // Q_OS_WIN
#ifdef Q_OS_LINUX
#include <unistd.h>
#endif // Q_OS_LINUX
////////////////////////////////////////////////
//
// Worker Object
//
////////////////////////////////////////////////
class Worker : public QObject {
Q_OBJECT
public:
QReadWriteLock lock;
bool running;
public slots:
void loop() {
qDebug() << "entering the loop";
bool _running;
forever {
lock.lockForRead();
_running = running;
lock.unlock();
if (!_running) return;
qDebug() << "loop iteration";
#ifdef Q_OS_WIN
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
WaitForSingleObject(event, INFINITE);
#endif // Q_OS_WIN
#ifdef Q_OS_LINUX
read(0, 0, 1);
#endif // Q_OS_LINUX
}
}
};
////////////////////////////////////////////////
//
// Controller
//
////////////////////////////////////////////////
class Controller {
public:
Controller() {
myWorker.connect(&myThread, SIGNAL(started()), &myWorker, SLOT(loop()));
myWorker.moveToThread(&myThread);
myThread.start();
}
~Controller() {
// Safely close threads
myWorker.lock.lockForWrite();
myWorker.running = false;
myWorker.lock.unlock();
myThread.quit();
//myThread.wait();
//myThread.exit();
//myThread.terminate();
}
private:
QThread myThread;
Worker myWorker;
};
#endif // CONTROLLER_H
For Linux:
Sending a signal to the thread with pthread_kill() interrupted read() with failure code EINTR. sigaction() was used to register the signal, and the signal thrown was SIGUSR1.
// Global scope
void nothing(int signum) {}
...
// Within the start of the thread
pthread_t myThreadID = pthread_self(); // Get the thread ID
struct sigaction action;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
action.sa_handler = nothing;
sigaction(SIGUSR1, &action, NULL);
...
// When it's time to close the thread
pthread_kill(myThreadID, SIGUSR1);
For Windows:
Signaling the OVERLAPPED's hEvent with SetEvent() was used to unblock GetOverlappedResult().
// Store a reference to the event
HANDLE myEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
...
// Within the start of the thread
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = myEvent;
...
// When it's time to close the thread
SetEvent(myEvent);

How to use signals & slots in Qt for inter-threading communication

I want to make an application where the user will hit a QPushButton and this will trigger a secondary thread which will add some text to a QListWidget in the main window. But for a reason that I cannot figure out ,although the signal from the thread to the main window is emitted it never reaches the destination. Probably because the connection fails. But why this happens here is my code(my application is compiled using Visual Studio 2010):
mythread.h
#ifndef MY_THREAD_H
#define MY_THREAD_H
#include <QThread>
#include <QString>
class mythread:public QThread
{
Q_OBJECT
public:
void setName(QString& name);
signals:
void sendMsg(QString& msg);
protected:
void run();
private:
QString m_name;
QString msg;
};
#endif
mythread.cpp
#include "mythread.h"
void mythread::setName(QString& name)
{
m_name=name;
}
void mythread::run()
{
msg="Hello "+m_name;
emit sendMsg(msg);
}
mydialog.h:
#ifndef MY_DIALOG_H
#define MY_DIALOG_H
#include <QtGui>
#include "mythread.h"
class mydialog:public QDialog
{
Q_OBJECT
public:
mydialog();
public slots:
void receiveMsg(QString& msg);
void fillList();
private:
QListWidget list1;
QPushButton btn1;
QGridLayout layout;
mythread thread;
};
#endif
mydialog.cpp:
#include "mydialog.h"
mydialog::mydialog()
{
layout.addWidget(&list1,0,0);
btn1.setText("Find");
layout.addWidget(&btn1,0,1);
setLayout(&layout);
QString myname="leonardo";
thread.setName(myname);
connect(&btn1,SIGNAL(clicked()),this,SLOT(fillList()));
connect(&thread,SIGNAL(sendMsg(QString&)),this,SLOT(receiveMsg(Qstring&)));
}
void mydialog::fillList()
{
thread.start();
}
void mydialog::receiveMsg(QString& msg)
{
list1.addItem(msg);
}
find.cpp:
#include <QApplication>
#include "mydialog.h"
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
mydialog window;
window.setWindowTitle("Find");
window.show();
return app.exec();
}
find.pro:
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += mydialog.h mythread.h
SOURCES += find.cpp mydialog.cpp mythread.cpp
Two things:
In your second connect call, Qstring must be changed to QString
Qt cannot deliver QString& accross threads by default. There's two ways to fix this:
Change your Signals and Slots and the connect to use QString rather than QString&
Use qRegisterMetaType in order to make QString& usable.
I still recommend reading
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
and Kari's comment
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong#commento-comment-name-a6fad43dec11ebe375cde77a9ee3c4331eb0c5f0bcac478ecbe032673e8ebc82
when working with threads, though.
First of all use const qualifier for arguments if you're not planning to modify it. After fixing typo in connection SLOT(receiveMsg(Qstring&)) and changing signals and slots signature to const references everything works fine

Creating a QWidget in a non-GUI thread

Yes, I know that you cannot use GUI things from non-GUI threads. However, it seems reasonable to be able to create a QWidget object, send it to the GUI thread, and then send signals to it. However, when I try to do so, I get errors that widgets cannot be moved. However, this seems to works:
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QDialog>
class BasicViewer : public QDialog
{
Q_OBJECT
public:
void Function(const float a)
{
std::cout << a << std::endl;
}
};
struct BasicViewerWrapper : public QObject
{
Q_OBJECT
public:
BasicViewer WrappedBasicViewer;
void Function(const float a)
{
WrappedBasicViewer.Function(a);
}
};
#include "main.moc" // For CMake's automoc
void Function2()
{
BasicViewerWrapper basicViewerWrapper;
basicViewerWrapper.moveToThread(QCoreApplication::instance()->thread());
basicViewerWrapper.Function(2.0f);
}
void Function1()
{
Function2();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtConcurrent::run(Function1);
std::cout << "End" << std::endl;
return app.exec();
}
I have created a wrapper class with the same API as the QWidget that stores an instance of the QWidget I wanted to create directly. I AM allowed to create that wrapper, move it to the GUI thread, and then use it. My question is, is there a way to do this without having to write this wrapper? It seems quite tedious, and since the concept works, I don't understand why it cannot be done directly. Any thoughts?
----------- EDIT ---------------
The first example was a bad one, because it did not attempt to do anything with GUI elements. This example indeed generates "Cannot create children for a parent that is in a different thread."
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class BasicViewer : public QMessageBox
{
Q_OBJECT
public:
};
struct BasicViewerWrapper : public QObject
{
Q_OBJECT
public:
BasicViewer WrappedBasicViewer;
void exec()
{
WrappedBasicViewer.exec();
}
};
#include "main.moc" // For CMake's automoc
void Function2()
{
BasicViewerWrapper basicViewerWrapper;
basicViewerWrapper.moveToThread(QCoreApplication::instance()->thread());
basicViewerWrapper.exec();
}
void Function1()
{
Function2();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtConcurrent::run(Function1);
return app.exec();
}
----------- EDIT 2 ----------------
I thought this would work, since the member object gets created after the thread of the Wrapper has been moved:
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class BasicViewer : public QMessageBox
{
Q_OBJECT
public:
};
struct BasicViewerWrapper : public QObject
{
Q_OBJECT
public:
BasicViewer* WrappedBasicViewer;
void exec()
{
WrappedBasicViewer->exec();
}
void create()
{
WrappedBasicViewer = new BasicViewer;
}
};
#include "main.moc" // For CMake's automoc
void Function2()
{
BasicViewerWrapper basicViewerWrapper;
basicViewerWrapper.moveToThread(QCoreApplication::instance()->thread());
basicViewerWrapper.create();
basicViewerWrapper.exec();
}
void Function1()
{
Function2();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtConcurrent::run(Function1);
return app.exec();
}
Unfortunately, it does not. Can anyone explain why?
--------------- EDIT 3 --------------------
I'm unsure why this works? It uses a signal to trigger the GUI component, but isn't the GUI object (the QDialog) still created in the non-GUI thread?
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class DialogHandler : public QObject
{
Q_OBJECT
signals:
void MySignal(int* returnValue);
public:
DialogHandler()
{
connect( this, SIGNAL( MySignal(int*) ), this, SLOT(MySlot(int*)), Qt::BlockingQueuedConnection );
}
void EmitSignal(int* returnValue)
{
emit MySignal(returnValue);
}
public slots:
void MySlot(int* returnValue)
{
std::cout << "input: " << *returnValue << std::endl;
QMessageBox* dialog = new QMessageBox;
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
dialog->setText("Test Text");
dialog->exec();
int result = dialog->result();
if(result == QMessageBox::Yes)
{
*returnValue = 1;
}
else
{
*returnValue = 0;
}
delete dialog;
}
};
#include "main.moc" // For CMake's automoc
void MyFunction()
{
DialogHandler* dialogHandler = new DialogHandler;
dialogHandler->moveToThread(QCoreApplication::instance()->thread());
int returnValue = -1;
dialogHandler->EmitSignal(&returnValue);
std::cout << "returnValue: " << returnValue << std::endl;
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtConcurrent::run(MyFunction);
std::cout << "End" << std::endl;
return app.exec();
}
Qt insists that widgets be created within the GUI thread. It disables moving widgets to different threads to prevent them from existing outside of the GUI thread. Your example above does not, in fact, move the BasicViewer to a different thread; it only moves BasicViewerWrapper to a different thread. You can see this if you print out the pointer to the containing thread within BasicViewerWrapper::Function and BasicViewer::Function:
std::cout << std::hex << thread() << std::endl;
If you really wish to trigger the creation of widgets from outside the GUI thread, it is more advisable for other threads to notify the GUI thread to create the widgets that you desire. You can either emit a signal from the non-GUI thread that connects to a slot in the GUI thread that creates the widgets, or you can invoke a function within the GUI thread to create the widgets for you using QMetaObject::invokeMethod.
EDIT
Unfortunately, there is no way to invoke a method in a different thread other than QMetaObject::invokeMethod if you are attempting to perform the invocation outside of a QObject. In the past, I've tried to tackle readability by placing the method invocation in a separate class or function, but admittedly, it's not perfect.
Your 3rd example is not working because QObject::moveToThread is not synchronous. Control must return to the destination thread's event loop before the object is actually moved to the destination thread. As such, you probably need a combination of a sleep statement and a call to QCoreApplication::processEvents after calling moveToThread. After these calls, you should probably call basicViewerWrapper::create() and basicViewerWrapper::exec() via QMetaObject::invokeMethod.

Resources