Qt GUI user interaction with QMessageBox from within QThread object - multithreading

I'm using QThread with MyObject->moveToThread(myThread); for communication functions that take a while. A few Signals and Slots keep the GUI posted about the progress.
Howeever, some situation may occur during the threaded communication that requires user interaction - since a QMessageBox can't be created inside a thread, I was thinking to emit a signal that would allow me to pause the thread and show the dialog. But first of all, there does not seem to be a way to pause a thread, and second, this attempt probably fails because it requires a way to pass a parameter back to the thread when resuming it.
A differenet approach might be to pass all parameters in question to the thread beforehand, but this may not alway be an option.
How is this usually done?
Edit
Thanks for the comment #1 and getting my hopes up, but please elaborate on how to create e.g. a dialog from an object within a thread and how to pause it..
The following example code with Qt 4.8.1 and MSVC++ 2010 results in:
MyClass::MyClass created
MainWindow::MainWindow thread started
MyClass::start run
ASSERT failure in QWidget: "Widgets must be created in the GUI thread.", file kernel\qwidget.cpp, line 1299
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "myclass.h"
#include <QThread>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QThread *thread = new QThread();
MyClass* myObject = new MyClass();
myObject->moveToThread( thread );
connect(thread, SIGNAL( started()), myObject, SLOT(start()));
connect(myObject, SIGNAL( finished()), thread, SLOT(quit()));
connect(myObject, SIGNAL( finished()), myObject, SLOT(deleteLater()));
connect(thread, SIGNAL( finished()), thread, SLOT(deleteLater()));
thread->start();
if( thread->isRunning() )
{
qDebug() << __FUNCTION__ << "thread started";
}
}
MainWindow::~MainWindow()
{
delete ui;
}
myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0);
signals:
void finished();
public slots:
void start();
};
#endif // MYCLASS_H
myclass.cpp
#include "myclass.h"
#include <QMessageBox>
#include <QDebug>
MyClass::MyClass(QObject *parent) :
QObject(parent)
{
qDebug() << __FUNCTION__ << "created";
}
void MyClass::start()
{
qDebug() << __FUNCTION__ << "run";
// do stuff ...
// get information from user (blocking)
QMessageBox *msgBox = new QMessageBox();
msgBox->setWindowTitle( tr("WindowTitle") );
msgBox->setText( tr("Text") );
msgBox->setInformativeText( tr("InformativeText") );
msgBox->setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel);
msgBox->setDefaultButton( QMessageBox::Ok);
msgBox->setEscapeButton( QMessageBox::Cancel);
msgBox->setIcon( QMessageBox::Information);
int ret = msgBox->exec();
// continue doing stuff (based on user input) ...
switch (ret)
{
case QMessageBox::Ok:
break;
case QMessageBox::Cancel:
break;
default:
break;
}
// do even more stuff
emit finished();
}

Use Qt::BlockingQueuedConnection in a signal/slot connection (the call to QObject::connect()).
http://doc.qt.digia.com/qt/qt.html#ConnectionType-enum
This will block your thread until the slot on the UI thread returns, the slot in the UI thread is then free to display a messagebox/modal dialog/whatever you want to do.
You must be sure that your worker thread is actually not on the UI thread, because as the docs say this will cause a dead lock if the signal and slot are on the same thread (since it will block itself).

I can't give any specific code right now, but I would do it like this:
In MyClass::start() lock a QMutex.
Emit a signal e.g. messageBoxRequired().
Wait on a shared QWaitCondition on the recent mutex. This will also unlock the mutex while the thread is waiting.
In a slot in your MainWindow, e.g. showMessageBox(), show the message box.
Store the returned value in a member of MyClass. You can do this by offering a setter and getter which use the mutex in order to protect the member. Obviously MyClass itself should only access that member with those setters/getters itself. (Also see QMutexLocker for that).
Call wakeOne() or wakeAll() on the shared QWaitCondition.
The previous wait() call will return and MyClass::start() will continue execution. If I understand the docs correctly, QWaitCondition will lock the mutex again before it returns from wait(). This means you have to unlock the mutex directly after the wait() call.
You can access the message box's return value from your class member (using a thread-safe getter)
Implementations for thread-safe setters/getters would be as follows:
void MyClass::setVariable( int value )
{
QMutexLocker( &_mutex );
_value = value;
}
int MyClass::getVariable() // Not sure if a 'const' modifier would work here
{
QMutexLocker( &_mutex );
return _value;
}

Related

Make scope of lock smaller in threadsafe queue

I have a dll which has a high priority functionality that runs in a high priority thread. This dll needs to report progress. Basically a callback system is used. The issue is that the dll has no control over the amount of time the callback takes to complete. This means the high priority functionality is dependent on the implementation of the callback which is not acceptable.
The idea is to have a class inbetween that buffers the progress notifications and calls the callback.
I'm new to C++11 and it's threading functionality and trying to discover the possibilities. I have an implementation but I have an issue(at least one that I see now). When the thread awakens after the wait the mutex is reacquired and stays acquired until the next wait. This means the lock is acquired for as long as the lengthy operation continues. Adding progress will block here. Basically a lot of code for no gain. I thought of changing the code to this but I don't know if this is the correct implementation.
Progress progress = queue.front();
queue.pop();
lock.unlock();
// Do lengthy operation with progress
lock.lock();
I think I need to wait for the condition variable, but that should not be connected to the lock. I don't see how this can be done. Pass a dummy lock and use a different lock to protect the queue? How should this problem be tackled in C++11?
header file
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <queue>
#include "Error.h"
#include "TypeDefinitions.h"
struct Progress
{
StateDescription State;
uint8 ProgressPercentage;
};
class ProgressIsolator
{
public:
ProgressIsolator();
virtual ~ProgressIsolator();
void ReportProgress(const Progress& progress);
void Finish();
private:
std::atomic<bool> shutdown;
std::condition_variable itemAvailable;
std::mutex mutex;
std::queue<Progress> queue;
std::thread worker;
void Work();
};
cpp file
#include "ProgressIsolator.h"
ProgressIsolator::ProgressIsolator() :
shutdown(false),
itemAvailable(),
worker([this]{ Work(); }),
progressCallback(progressCallback),
completedCallback(completedCallback)
{
// TODO: only continue when worker thread is ready and listening?
}
ProgressIsolator::~ProgressIsolator()
{
Finish();
worker.join();
}
void ProgressIsolator::ReportProgress(const Progress& progress)
{
std::unique_lock<std::mutex> lock(mutex);
queue.push(progress);
itemAvailable.notify_one();
}
void ProgressIsolator::Finish()
{
shutdown = true;
itemAvailable.notify_one();
}
void ProgressIsolator::Work()
{
std::unique_lock<std::mutex> lock(mutex);
while (!shutdown)
{
itemAvailable.wait(lock);
while (!queue.empty())
{
Progress progress = queue.front();
queue.pop();
// Do lengthy operation with progress
}
}
}
void ProgressIsolator::Work()
{
while (!shutdown)
{
Progress progress;
{
std::unique_lock<std::mutex> lock(mutex);
itemAvailable.wait(lock, [this] { return !queue.empty(); });
progress = queue.front();
queue.pop();
}
// Do lengthy operation with progress
}
}

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.

Qt4 connect QThread signal with main thread slot

All right here we go:
This is all over the internet, but it does not seems to be working for me, the thing is I have two threads, Worker and p4, p4 sends a time to wait and other params to the worker, and I want that to be processed in a different thread, but then update the main thread with the results.
so, Worker.h looks like this:
#include <QObject>
class Worker : public QObject
{
Q_OBJECT
public:
int time;
int actual_weight;
int supported_weigth;
Worker();
~Worker();
public slots:
void process();
signals:
void finished();
};
Worker.cpp looks like this:
#include "worker.h"
#include <QDebug>
#include <iostream>
using namespace std;
Worker::Worker()
{
}
Worker::~Worker(){
}
void Worker::process(){
cout << "sleep!" << endl;
sleep(this->time);
cout << "done!" << endl;
//more_nonsense_stuff();
emit finished();
}
and then in my main thread I have this:
QThread* t = new QThread;
Worker* w = new Worker();
w->time = this->transactions[i].time;
connect(t, SIGNAL(started()), w, SLOT(process()));
connect(w, SIGNAL(finished()), this, SLOT(update_gui()));
w->moveToThread(t);
t->start();
the thing is that the SLOT update_gui() is defined in the main window header and implemented in the .cpp, but it never gets to execute.
I have tried attaching Qt::DirectConnection, and the gui updates, but when worker is finished... the whole program closes.
I've looked this but didn't worked for me (or I didn't understand), also looked at this but that says what I'm trying to do is unsafe??
please help, what am I doing wrong?

Resources