I'm looking for correct pattern to use it in Qt-based app for async processing.
this is a simplified class which should receive a signals
class Receiver : public QObject {
Q_OBJECT
public:
explicit Receiver(QObject *parent = nullptr) : QObject(parent) { }
public slots:
void onNewMessage(Message message) {
// ...
}
};
the creating of the instance of this class is a dynamic (also simplifed, really - an array of the objects for message processing).
Receiver* r;
// ...
if (r == nullptr) {
r = new Receiver{};
r->moveToThread(new QThread);
connect(this, &MessageGenerator::messageCompleted, r, &Receiver::onNewMessage);
}
in main function also exists a registration:
qRegisterMetaType<Message> ("Message");
the question is why slot is never called?
in case of the removing Thread stuff (moveTOThread) then all works fine ,
but I'd prefer to have a processing in event loops in different threads
According to the doc:
Constructs a new QThread to manage a new thread. The parent takes ownership of the QThread. The thread does not begin executing until start() is called.
Do you call method start, like this?
r = new Receiver{};
t = new QThread();
r->moveToThread(t);
connect(this, &MessageGenerator::messageCompleted, r, &Receiver::onNewMessage);
t->start();
Related
From the thread context of a slot in my QT GUI application (upon button push), I am trying to launch a worker thread to update other another part of the GUI with the results of a CPU intensive calculation - these results will update a table or a google like map widget - so this needs to occur in the main QT application thread where it is safe to update these widgets.
The problem I have is that the updateGUIWidget slot never gets called unless I change the connection type to Qt::DirectConnection - in which case it gets called in the worker thread (where it is unsafe to update the GUI). I checked the results of each of the connect calls and they are fine, it seems that there is some issue with the event loop somewhere. I'm not sure if I need to allocate the thread and the worker objects as members of the mainwindow or if its OK to do so from stack variables in the slot.
void
mainwindow::on_importSimulatedFlight_clicked()
{
// experimental worker thread model adapted from YouTube tutorial
// by Giuseppe di Angelo https://www.youtube.com/watch?v=BgqT6SIeRn4
// auto thread = new QThread;
// note worker created in gui thread here - we will move its thread
// affinity to 'thread' below before starting it.
auto thread = new QThread;
auto worker = new Worker;
connect(thread, &QThread::started, worker, &Worker::doWork);
// connect(worker, &Worker::progressUpdate, this, &mainwindow::updateGUIWidget, Qt::DirectConnection);
connect(worker, &Worker::progressUpdate, this, &mainwindow::updateGUIWidget, Qt::QueuedConnection);
connect(worker, &Worker::workDone, thread, &QThread::quit);
connect(thread, &QThread::finished, worker, &Worker::deleteLater);
// move worker to separate thread
worker->moveToThread(thread);
thread->start();
}
The mainwindow has a slots declared in mainwindow.h as follows:
class mainwindow : public QMainWindow
{
Q_OBJECT
public:
explicit mainwindow(QWidget *parent = Q_NULLPTR);
~mainwindow();
...
public slots:
void on_importSimulatedFlight_clicked();
void updateGUIWidget(const param& rParam);
...
}
and implemented in mainwindow.cpp as follows:
void
mainwindow::updateGUIWidget(const param& rParam)
{
... update widget components with rParam partial result here
}
and my worker is as follows:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork() {
const QString result;
for (int i=0; i<5; i++) {
const MMRTimedRecord foo;
// QThread::sleep(1);
emit progressUpdate(foo);
}
emit workDone(result);
}
signals:
void progressUpdate(const MMRTimedRecord&);
void workDone(const QString &result);
};
The reason it isn't working is because there's a serious flaw in your code: you are trying to emit a reference to a local variable to be handled in an slot on a different thread. That is a recipe for disaster.
When you are using Qt::QueuedConnection, you MUST emit by value, like this:
void progressUpdate(MMRTimedRecord val);
That means that your MMRTimedRecord must be copyable, and correspondingly, your slot must also accept by value. And why is there a mismatch between the signal progressUpdate(const MMRTimedRecord&) and the slot updateGUIWidget(const param& rParam); ?
You can check this answer for a possible solution. You can do
MainThreadEvent::post([&]()
{
// gui update stuff
}
);
in your slot to do the gui update in the main thread, but it is a crude approach to be sure. Despite this, I do something like this all the time. Be careful of dangling pointers and references (use QPointer)..., as the issued event is independent of the issuing object. Alternatively, use the timer approach.
It’s really easy – and you shouldn’t be managing any threads manually:
void Ui::slot() {
QtConcurrent::run([this]{
auto result = compute();
QMetaObject::invokeMethod(this, [this, r = std::move(result)]{
m_widget.setSomething(r);
});
});
}
The type of the data you compute should be movable.
I'm confused about threads and event loops in Qt.
A QThread normally runs exec() in run(). But when you override run(), there will not be an event loop.
This (older) doc states that calling deleteLater() on objects that are created in a thread without an event loop doesn't work:
If no event loop is running, events won't be delivered to the object.
For example, if you create a QTimer object in a thread but never call
exec(), the QTimer will never emit its timeout() signal. Calling
deleteLater() won't work either. (These restrictions apply to the main
thread as well.)
However, look at the following code:
class MyObject : public QObject
{
Q_OBJECT
QString content;
public:
MyObject(QObject *parent = 0);
~MyObject();
};
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
signals:
public slots:
};
MyObject::MyObject(QObject *parent) :
QObject(parent),
content("foobar")
{}
MyObject::~MyObject()
{
// This code is still executed before I close the program. How?
qDebug() << "Destroying MyObject";
}
MyThread::MyThread(QObject *parent) :
QThread(parent)
{}
void MyThread::run()
{
// Creating a heap object in a thread that does not have
// an event loop (because I reimplemented run()).
MyObject * objectification = new MyObject();
sleep(1);
objectification->deleteLater();
}
So why does the deletelater() call still post an event that is picked up?
As the Qt docs state for deleteLater: -
Since Qt 4.8, if deleteLater() is called on an object that lives in a thread with no running event loop, the object will be destroyed when the thread finishes.
The object is still being deleted when no event loop exists. If you look at the source code for QObject::deleteLater, you'll see that an event is posted:-
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
So, let's look at what happens when a thread is deleted. QThreadData's destructor includes this:-
for (int i = 0; i < postEventList.size(); ++i) {
const QPostEvent &pe = postEventList.at(i);
if (pe.event) {
--pe.receiver->d_func()->postedEvents;
pe.event->posted = false;
delete pe.event;
}
}
As we see, although there's no event loop, the event list is still available.
If we look more closely into QThreadPrivate (just taking one platform as an example, in this case unix), you'll see that when the thread finishes, it forwards all deferred deleted messages, so they can continue to be processed:
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
I have got some problem in Qt.
I assign some parameters in GUI thread:
newton.h (work thread) :
class Newton : public QThread
resic.cpp (GUI thread) :
.
.
.
Newton mythread;
resic::resic(QWidget *parent) :
QWidget(parent),
ui(new Ui::resic)
{
ui->setupUi(this);
mythread.start();
}
void resic::on_PushButton_clicked()
{
w1=ui->doubleSpinBox_2->value();
um1=ui->doubleSpinBox->value();
alpha1=ui->doubleSpinBox_3->value();
et01=ui->doubleSpinBox_4->value();
Er1=ui->doubleSpinBox_11->value();
Rx1=ui->doubleSpinBox_12->value();
xa1=ui->doubleSpinBox_8->value();
xb1=ui->doubleSpinBox_9->value();
q1=ui->doubleSpinBox_10->value();
ya1=(q1-2*q1);
yb1=ui->doubleSpinBox_10->value();
maxl1=ui->spinBox->value();
}
And I want to send these parameters after click on the button to the work thread and then run some calculation in this work thread.
But I don't know how send parameters.
Can you give me some advice, please?
Thank you very much.
A simple solution to running a piece of code in a worker thread is to leverage Qt Concurrent framework. Another solution is to put the worker into a QObject, and use a QThread directly.
struct Parameters {
double w1, um1, alpha1, et01, ...;
};
struct Result {
...
};
Result calculate(const Parameters & p) {
...
}
class resic : public QWidget {
...
QFutureWatcher<Result> m_futureWatcher;
QScopedPointer<Ui::resic> ui;
Q_SLOT void onResults();
...
};
resic::resic(QWidget * parent) : QWidget(parent), ui(new Ui::resic)
{
connect(&m_futureWatcher, SIGNAL(finished()), SLOT(onResults()));
}
resic::~resic() {}
Parameters resic::get()
{
Parameters p;
p.w1=ui->doubleSpinBox_2->value();
p.um1=ui->doubleSpinBox->value();
p.alpha1=ui->doubleSpinBox_3->value();
p.et01=ui->doubleSpinBox_4->value();
...
return p;
}
void resic::on_PushButton_clicked()
{
Parameters const p(get());
QFuture<Result> future = QtConcurrent::run(&calculate);
m_futureWatcher.setFuture(future);
}
void resic::onResults()
{
Result const r = m_futureWatcher.result();
...
}
It is important to remember that a QThread object usually lives in the thread where it was created, not in the thread that it manages. This oft-overlooked detail means that a QThread's slots will be executed in the context of its home thread, not in the context of the thread it is managing. For this reason, implementing new slots in a QThread subclass is error-prone and discouraged.
You can inherit the class "Newton" from QObject create your object of this class on the heap and move it to a new thread.
It can be done like:
mythread = new Newton();
QThread * th = new QThread();
mythread->moveToThread(th);
QObject::connect(th,SIGNAL(started()),mythread,SLOT(OnStarted()));
QObject::connect(th,SIGNAL(finished()),mythread,SLOT(OnFinished()));
th->start();
Your initialization and termination tasks in the class Newton should be done in OnStarted() and OnFinished() slots respectively.
Now you can implement a slot in your worker thread which runs the calculations. You can connect a signal in your GUI thread to that slot which contains the arguments you want to send. When emitting that signal along the arguments, the calculation slot in the working thread is started with the appropriate arguments.
From reading this blog, this blog and some others, Subclassing QThread is bad practice. So I tried to apply this method.
But my problem is that I have a QTimer and a QTcpSocket in the class I want to move to a different thread. Suddenly, it's not as easy as it the examples used. :(
QThread m_commsThread;
m_pICommsHandler = new CommsHandlerIP();
m_pICommsHandler->moveToThread(&m_commsThread);
m_commsThread.start();
And here is the CommsHandlerIP class, methods are not included.
class CommsHandlerIP : public QObject
{
Q_OBJECT
public:
CommsHandlerIP();
~CommsHandlerIP(void);
protected:
QTcpSocket m_TCPSocket;
QTimer m_timer;
}
Issue is that the QTimer and the QTcpSocket (inside CommsHandlerIP class) are in the main thread even if you move CommsHandlerIP. So I can't start the timer or connect the socket.
If I try to moveToThread the QTimer and QTcpSocket (inside the constructor by passing the thread pointer for instance), this become really messy when I leave the app.
What should I do?
Class Instances are created on the calling thread.
QTimer inherits QObject.
Each Thread on Qt can have an event loop if it calls exec().
so you want to move QTimer to an event loop on another thread.
so you should manually move it.
Therefore, delay their creation until after you move the object: -
class CommsHandlerIP : public QObject
{
Q_OBJECT
public slots:
void Initialise();
private:
void Run();
// c++ 11, initialising in headers...
QTimer* m_pTimer = NULL;
QTcpSocket* m_pSocket = NULL;
};
void CommsHandlerIP::Initialise()
{
m_pTimer = new QTimer(this);
m_pSocket = new QTcpSocket(this);
Run();
}
QThread m_commsThread;
m_pICommsHandler = new CommsHandlerIP();
// Note Qt 5 connect style
connect(&m_commsThread, &QThread::started, m_pICommsHandler, &CommsHandlerIP::Initialise);
m_pICommsHandler->moveToThread(&m_commsThread);
m_commsThread.start();
When the thread is started, the CommsHanderIP Initialise function is called; this is where you should create and setup the QTcpSocket and QTimer objects before calling Run(). As the CommsHandlerIP is running in the new thread before creating those objects, they will also share the same thread affinity.
There is a much simpler method of achieving all this that follows the same algorithm but doesn't involve all the boilerplating needed to create threads and changing thread affinities, using QRunnable and QThreadPool
If I convert Merlin069's example, you'll see how it simplifies the code a bit:
class CommsHandlerIP : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
public slots:
//... any slots
signals:
//... any signals
private:
// c++ 11, initialising in headers...
QTimer* m_pTimer = NULL;
QTcpSocket* m_pSocket = NULL;
};
void CommsHandlerIP::run()
{
m_pTimer = new QTimer();
m_pSocket = new QTcpSocket();
//...
delete m_pTimer;
delete m_pSocket;
}
QThreadPool::globalInstance()->start(new CommsHandlerIP);
I stumbled across this when searching on Timer behaviour and movetoThread.
The accepted answer is a good work-around but not really the root cause of the problem. There is a general rule that when you move an object then all child objects will move as well. So you just need to make sure that the QTimer becomes a child so pass the this pointer in its constructor.
CommsHandlerIPL::CommsHandlerIP()
: QObject(), m_pTimer(new QTimer(this)) // <=== crucial to make it a "child" object
{
}
I created an application that has a mainwindow and from this window creates a QDialog. This QDialog should create a RenderThread that emits received images from the camera or in the example emits text. When i debug this it seems that the connection is never made as adding a breakpoint in the slot CameraWindow::debugSomething does not get caught. Whats wrong ?
I followed this example: http://qt-project.org/doc/qt-4.8/threads-mandelbrot.html but it seems that i've done something wrong.
qtDEVC::qtDEVC(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
connect (ui.pushButton_startCam, SIGNAL( clicked() ),this,SLOT( startCam() ) );
/**Threading*/
CameraWindow camWindow = new CameraWindow(this);
}
int qtDEVC::startCam()
{
camWindow.show();
camWindow.startCaptureThread();
}
CameraWindow Class:
CameraWindow::CameraWindow(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
}
void CameraWindow::debugSomething(std::string something){
QString somethings(something.c_str());
qDebug()<<somethings;
}
int CameraWindow::startCaptureThread(){
RenderThread *thread = new RenderThread(this, guid, CLEYE_COLOR_RAW, CLEYE_VGA, 50);
thread->StartCapture(); //starts thread in low priority and sets _running to true
}
CameraWindow header
class CameraWindow : public QDialog
{
Q_OBJECT
public:
CameraWindow(QWidget *parent = 0);
~CameraWindow();
Ui::CameraWindow ui;
public slots:
int startCaptureThread();
void debugSomething(QString);
private:
RenderThread thread;
};
RenderThread Class
void RenderThread::run()
{
// image capturing loop
while(_running)
{
qDebug()<<("render while()"); //is printed with qdebug correctly
if (restart)
break;
if (abort)
return;
qDebug("it"); //is also printed with qdebug correctly
emit sendText(text);
}
RenderThread header
class RenderThread : public QThread
{
Q_OBJECT
public:
RenderThread(QObject *parent, GUID cameraGUID, CLEyeCameraColorMode mode, CLEyeCameraResolution resolution, float fps);
RenderThread();
~RenderThread();
bool StartCapture();
signals:
void sendText(QString &text);
protected:
void run();
private:
QMutex mutex;
QWaitCondition condition;
//some more private variables for construction
};
I think that this creation seems somehow wrong: RenderThread *thread = new RenderThread(this);
The first thing that's worrying about the question is the word "RenderThread". Note that Qt only allows rendering on the main thread. You can create separate threads for calculations of image data, but whenever you use a painter and draw objects, that must happen on the main thread. However, If you're just going to capture the image and pass that to the main thread, via signals and slots, then that should be ok.
Secondly, whilst you've not shown all your code, I'm assuming from the function called RenderThread::run() and from the Qt example that you may have inherited from QThread here. If this is the case, please note that this is not how to use QThread. Instead, you should have your class inherit from QObject and move that to a QThread. You can read about how to use QThread properly here.
I know it's a Qt example that you've followed, but even the guys at Qt think it's a bad idea. Here's an article of how to really use QThreads.
With that in mind, here's an outline of how I would use QThread for this: -
class CameraWindow : public QDialog
{
private:
CameraObject* m_pCamObject;
};
class CameraObject : public QObject
{
Q_OBJECT
public:
private slots:
startCaptureThread();
private:
};
int CameraWindow::startCaptureThread()
{
m_pCamObject = new CameraObject;
QThread* pThread = new QThread;
this->moveToThread(pThread); // CameraObject will run on the new thread
connect(pThread, SIGNAL(started()), m_pCamObject, SLOT(startCaptureThread()));
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()); // clear up when
finished
pThread->start();
}
Note that here is a CameraObject, separated from the CameraWindow. The QThread is just a controller of the thread and keeps a clean separation from the CameraObject.
Another reason for handling threads this way is that you can move multiple QObject instances to the new thread, rather than always creating a new thread per object. If you've more threads than CPU cores, you're unlikely to gain by creating yet another thread.
In the constructor of CameraWindow class, you are connecting a RenderThread's signal but it is not the same object which is started in startCaptureThread. Change your startCaptureThread like this:
int CameraWindow::startCaptureThread()
{
thread.StartCapture(); //starts thread in low priority and sets _running to true
}
In this method, the thread member of CameraWindow is started.
P.S.: post the headers too, we can't see the members from this code.
In the mentioned example, CameraWindow class holds a RenderThread thread variable, not a RenderThread *thread.
You are connecting a pointer address in your connect call:
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
Try to use a good address:
connect(thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
This is not a tested answer.