QT how to restart a thread? - qt

How to properly restart a QThread? I have been googling this four hours and can't find any concrete answer.
What I have is the basic moveToThread implementation:
VideoHandler::VideoHandler()
{
VideoBurner *videoBurner = new VideoBurner;
videoBurner->moveToThread(&videoBurnerThread);
connect(this, &VideoHandler::signalVideoData, videoBurner, &VideoBurner::setVideoData);
connect(this, &VideoHandler::signalVideoBurn, videoBurner, &VideoBurner::initVideoBurn);
// don't really want it since there is only 1 object
//connect(&videoBurnerThread, &QThread::finished, videoBurner, &QObject::deleteLater);
connect(videoBurner, &VideoBurner::burnProcess, this, [=](QString step, int percentage){
emit burningProcess(step, percentage);
});
}
This is the declaration of my Class:
class VideoHandler : public QObject
{
Q_OBJECT
QThread videoBurnerThread;
...
bunch of defintions
...
}
The VideoBurner class is also a subclass of QObject
class VideoBurner : public QObject
{
Q_OBJECT
...
bunch of definitions
...
}
For the first run this works perfect, signals and slots all work.
The issue happens when I want to "cancel" the thread.
For example it is working on some "heavy" calculation that I want to stop from the main thread so I call: videoBurnerThread.quit(); with a cancel function from VideoHandler.
I don't wait() on it as it would block the main thread.
quit() triggers &QThread::finished, but I commented out that connection as it destroys my only object instance.
(also I can't find any example that creates an object and puts it on a thread outside a constructor, if that's even possible? when I tried the app would just close without errors)
I found that the quit() only stops the event loop, not doing anything besides that, which leads to the issue of restarting the tread.
After I want to do the "heavy" stuff again, and I call videoBurnerThread.start(); to start it again, I get results of last performed function from VideoBurner and some signals from it, before it actually starts doing what it should.
Can I somehow stop whatever it was working on and just restart it? I tried sending an "abort" signal from VideoHandler so it doesn't emit signals, but that didn't work.
Do I absolutely need the &QObject::deleteLater so it stops? If so, how to reinitialize VideoBurner correctly inside some function and reconnect it's signal/slot?
Also there is no logic in VideoBurner destructor just a public: virtual ~VideoBurner(){};, could this be an issue?

Call "this->deleteLater()" at the end of your worker.
Connect the worker destroyed signal to the thread quit slot in your Handler function.
Refer to this code snippet.
if(!dataThread.isRunning())
{
worker = new Worker();
dataThread.setObjectName("dataThread");
worker->moveToThread(&dataThread);
QObject::connect(&dataThread, &QThread::started, worker, &Worker::run);
QObject::connect(worker, &Worker::destroyed, &dataThread, &QThread::quit);
QObject::connect(worker, &Worker::set_counter_label, this, &MainWindow::update_counter);
dataThread.start();
}

Related

QTimer timeout signal not being emitted

I have a subclass of QObject called Updater that I want to use to manage some widgets in my app. I want it to run updateDisp() every 16 ms, so I created a QTimer in the constructor and connected the timeout signal to the updateDisp() slot. However, updateDisp() never runs, and I can't for the life of me figure out why.
in updater.h:
class Updater : public QObject {
Q_OBJECT
ToUpdate* toUpdate;
QTimer* timer;
...
public slots:
void updateDisp();
};
in updater.cpp:
Updater::Updater(ToUpdate* t, QObject *parent)
: QObject(parent) {
toUpdate = t;
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateDisp()));
timer->setInterval(16);
timer->start();}
I instantiate an Updater object in MainWindow.cpp. Also, I have the GUI thread separate from main() (using winapi CreateThread()); I've seen some other posts about problems with QTimers and QThreads but obviously this is a bit different.
There's some similar issues.
I'd a similar problem in the past: https://github.com/codelol/QtTimer/commit/cef130b7ad27c9ab18e03c15710ace942381c82a#commitcomment-10696869
Basically it seems that Qt5 timer doesn't work as expected while in background, it's sync with the animation timer... which doesn't run often while in background.
This guy solved a similar issue setting the timer type to Qt::PreciseTimer
https://github.com/codelol/QtTimer/commit/cef130b7ad27c9ab18e03c15710ace942381c82a#commitcomment-10696869
timer->setTimerType(Qt::PreciseTimer);
The description of the timer types: http://doc.qt.io/qt-5/qt.html#TimerType-enum
Qt::PreciseTimer 0 Precise timers try to keep millisecond accuracy
Not sure if they're the exactly same problem, but you can give a try on that.

When is QThread quit() or finished()?

I'm new to Qt, and want to simply display a video in Qt GUI. I basically got everything figured out, except for some details handling the QThread, which is really annoying.
I reformulate my question into a simpler program, hope it will explains better
first I define this QObject class
#include <QObject>
#include <QDebug>
class myObject : public QObject
{
Q_OBJECT
public:
explicit myObject(QObject *parent = 0);
bool stop;
signals:
void finishWork();
public slots:
void dowork();
void onfinishThread();
};
myObject::myObject(QObject *parent) :
QObject(parent)
{
stop = true;
}
void myObject::dowork(){
qDebug()<<"start working!";
while(!stop){
qDebug()<<"working...";
}
emit finishWork();
qDebug()<<"finish do work!";
}
void myObject::onfinishThread(){
qDebug()<<"thread is finished!";
}
then the main function
#include <QCoreApplication>
#include <QThread>
#include <iostream>
#include <windows.h>
#include "myobject.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
myObject* myObj = new myObject();
QThread* myThread = new QThread;
myThread->connect(myObj, SIGNAL(finishWork()), SLOT(quit()));
myObj->connect(myThread, SIGNAL(started()), SLOT(dowork()));
myObj->connect(myThread, SIGNAL(finished()), SLOT(onfinishThread()));
myObj->moveToThread(myThread);
myObj->stop = false;
myThread->start();
cout<<"Press ENTER to continue....."<<endl<<endl;
cin.ignore(1);
myObj->stop = true;
Sleep(10);
if(myThread->isRunning()){
qDebug()<<"The thread is still running?!!!";
}
/*
myObj->stop = false;
Sleep(1000);
myThread->start();
myObj->stop = true;
*/
myObj->deleteLater();
myThread->deleteLater();
return a.exec();
}
As you can see, I even used cin to try let the dowork() run first, but it didn't work at all, the output is
so I'm really confused on how scheduling works for QThread...
Also, if you uncomment the part
/*
myObj->stop = false;
Sleep(1000);
myThread->start();
myObj->stop = true;
*/
the output is exactly the same! only stays a while after printing
The thread is still running?!!!
Would anyone help me with this? Thanks a lot. You may simply copy all the code and test it yourself.
-------------------------Original Question, bad explanation, please ignore....----------------------------------------
I made a videoObj Class with only one function to Query the frames, the function is defined as:
void videoObj::ProcessFrame(){
bool getframe;
qDebug()<<"get in ProcessFrame";
while(!stop_flag){
getframe = capture_.read(imgOriginal_);
if(!getframe){
qDebug()<<"Video End!";
break;
}
cv::cvtColor(imgOriginal_, imgOriginal_, CV_BGR2RGB);
QImage qimgOriginal((uchar*)imgOriginal_.data, imgOriginal_.cols, imgOriginal_.rows, imgOriginal_.step, QImage::Format_RGB888);
emit imgProcessed(qimgOriginal);
this->thread()->msleep(10);
//qDebug()<<"processing frames";
}
emit stopProcess();
qDebug()<<"Stop thread";
}
Basically above code is just query frames and whenever got one emit the
SIGNAL imgProcessed(qimgOriginal)
and whenever the stop_flag is set on, stop the while loop and emit the
SIGNAL stopProcess()
I use this class in the MainWindow Class, here is how I define the connection in the constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
video_obj_ = new videoObj();
video_thread_ = new QThread;
this->connect(video_obj_, SIGNAL(imgProcessed(QImage)), SLOT(onImgProcssed(QImage))); \\this is for displaying the image
video_obj_->connect(video_thread_, SIGNAL(started()), SLOT(ProcessFrame()));
video_obj_->moveToThread(video_thread_);
video_thread_->connect(video_obj_, SIGNAL(stopProcess()), SLOT(quit()));
}
Above code works fine in frame query. The problem I don't understand is, if I set video_obj_->stop_flag on in any MainWiow member function, the ProcessFrame() in videoObj Class should emit stopProcess() signal and trigger quit() of video_thread_, and then the thread should finish, that is video_thread_->finished() is true.
However, if I do something like:
connect(video_thread_, SIGNAL(finished()), this, SLOT(onStopProcess())); //onStopProcess() see below
void MainWindow::on_btnStart_clicked()
{
video_obj_->stop_flag = 1;
this->thread()->msleep(10);
video_obj_->capture_.open(ui->lineEditVidoeAddress->text().toStdString());
//... something about videoCapture setting here, not related
video_obj_->capture_.set(CV_CAP_PROP_POS_FRAMES, 0);
video_obj_->stop_flag = 0;
this->thread()->msleep(10);
if(video_thread_->isRunning()){
qDebug()<<"The thread is still running?!!!";
}
video_thread_->start();
}
void MainWindow::onStopProcess(){
qDebug()<<"thread is finished";
}
It will give me the output:
Stop thread
The thread is still running?!!!
thread is finished
Which means triggering the quit() is not finish the thread, or quit() has not been triggered.
If I use:
video_thread_->wait(); //instead of video_thread_->wait(10);
The program will just freeze.
Is anyone can help me with this, it really confuse me about this quit() and finished()...
Thanks!
Since when you call stop_flag=1, the video_thread_ finishes the current function which is
ProcessFrame
before ProcessFrame finish, quit is called on the video_thread_ through emit stopProcess().
However, quit is different from terminate, terminate can exit the thread any time (but it is not safe), quit works with the event loop, if the thread has no eventloop, quit has no effect.
I guess before qthread execute the next event in the eventloop, it checks some flag, which can be set by quit, it the flag is set by quit, then it won't execute the next event in the eventloop. Or it can also be that a quit event is inserted into the eventloop, and the next event in the eventloop will be quit.
After stop_flag = 1, you called video_thread_->wait, that will block the video_thread_ from executing the next event in the eventloop, thus the quit will not take effect before time out, however, the nextlines which print "not finished?!!!" is executed immediately. Instead of calling video_thread->wait, if you call currentThread()->Sleep(some_enough_time), then there will be time for the video_thread_ to execute the next event and quit.
You can read the Qt documentation of QThread, wait is used with terminate to terminate a thread synchronously.
============================== The new code ================================
When you do:
myObj->connect(myThread, SIGNAL(started()), SLOT(dowork()));
The signal source is myThread, the slot also belongs to myThread, since the object "myThread" is created in the main thread, thus as a object it lives in the main thread. You can call myThread->thread() to see this, it will return the main thread instead of the new thread.
However, the started signal is emitted from the new thread namely the thread that myThread represents, thus the connection is a Qt::QueuedConnection. dowork() is posted in the event queue of main thread, and it'll be executed only after a.exec() which executes the main threads eventloop.
The same thing happens to the other 2 connect calls, all the slots will be executed in the eventloop of the main thread.
First the start is emitted from the new thread when myThread->start is called, dowork is posted in the main thread's event queue.
Nothing really happens before you call a.exec();
So the program will go ahead to cin and then set stop to true, and then print "Thread is still running?!!".
Second When a.exec() is called, the dowork is executed in the main thread and "start work" is printed. Nothing is done because the stop flag is already true, and the finishwork signal is emitted from the main thread, print "finish do work";
Third The last step the finishwork is emitted, and the quit slot is directly called. However, before the new thread can really quit, the main thread has already finished the eventqueue, because no more events are posted to the main thread. The application exits without waiting for quit() to take effect.
To test this is true, do not modify any of your code, just add after
emit finishWork();
currentThread()->sleep(1000);
you will see "thread is finished!" printed, because this make time for the new thread to emit finished(), and the onfinishThread() will be add to the main thread's eventqueue.
BTW, your way of working with thread looks like java style, which is not the standard qt way. You can read this before you work on qt thread.
This is not a scheduling issue.
That you did in your code looks like:
Create a thread.
Then this thread emits a signal that it started, run slot dowork()
start a thread.
Wait for user input
echo about thread is running
execute event loop
At point 3 thread is already running and signalled about that. Because myObj is created in main thread and not moved to any other thread (to process events there), your thread does not do anything else now, but just spins event loop. At the same time event that tells you want to run myObj's dowork() is posted on the main thread. At last then it comes to step 6 you start to execute event loop of it, and first thing it finds is event that it needs to call dowork() on myObj.
To make it clear to you how Qt threads and signal-slot connection works, I recommend you to read this article on Qt blog.
In simple to fix it, you can move your object myObj to the thread that you wan't to run.
But to make this really correct, I bet that you really want is to subclass QRunnable and (re-)implement it's run method to do the stuff you wan't in QThread, so that thread does it's job, than finished correctly, so you can join on it. Or depending on your goal you might be even better with using QtConcurrent::run(aFunction)

Qthread - trouble shutting down threads

For the last few days, I've been trying out the new preferred approach for using QThreads without subclassing QThread. The trouble I'm having is when I try to shutdown a set of threads that I created. I regularly get a "Destroyed while thread is still running" message (if I'm running in Debug mode, I also get a Segmentation Fault dialog). My code is very simple, and I've tried to follow the examples that I've been able to find on the internet.
My basic setup is as follows: I've a simple class that I want to run in a separate thread; in fact, I want to run 5 instances of this class, each in a separate thread. I have a simple dialog with a button to start each thread, and a button to stop each thread (10 buttons). When I click one of the "start" buttons, a new instance of the test class is created, a new QThread is created, a movetothread is called to get the test class object to the thread...also, since I have a couple of other members in the test class that need to move to the thread, I call movetothread a few additional times with these other items. Note that one of these items is a QUdpSocket, and although this may not make sense, I wanted to make sure that sockets could be moved to a separate thread in this fashion...I haven't tested the use of the socket in the thread at this point.
Starting of the threads all seem to work fine. When I use the linux top command to see if the threads are created and running, they show up as expected.
The problem occurs when I begin stopping the threads. I randomly (or it appears to be random) get the error described above.
Class that is to run in separate thread:
// Declaration
class TestClass : public QObject
{
Q_OBJECT
public:
explicit TestClass(QObject *parent = 0);
QTimer m_workTimer;
QUdpSocket m_socket;
Q_SIGNALS:
void finished();
public Q_SLOTS:
void start();
void stop();
void doWork();
};
// Implementation
TestClass::TestClass(QObject *parent) :
QObject(parent)
{
}
void TestClass::start()
{
connect(&m_workTimer, SIGNAL(timeout()),this,SLOT(doWork()));
m_workTimer.start(50);
}
void TestClass::stop()
{
m_workTimer.stop();
emit finished();
}
void TestClass::doWork()
{
int j;
for(int i = 0; i<10000; i++)
{
j = i;
}
}
Inside my main app, code called to start the first thread (similar code exists for each of the other threads):
mp_thread1 = new QThread();
mp_testClass1 = new TestClass();
mp_testClass1->moveToThread(mp_thread1);
mp_testClass1->m_socket.moveToThread(mp_thread1);
mp_testClass1->m_workTimer.moveToThread(mp_thread1);
connect(mp_thread1, SIGNAL(started()), mp_testClass1, SLOT(start()));
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(quit()));
connect(mp_testClass1, SIGNAL(finished()), mp_testClass1, SLOT(deleteLater()));
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));
connect(this,SIGNAL(stop1()),mp_testClass1,SLOT(stop()));
mp_thread1->start();
Also inside my main app, this code is called when a stop button is clicked for a specific thread (in this case thread 1):
emit stop1();
Sometimes it appears that threads are stopped and destroyed without issue. Other times, I get the error described above.
Any guidance would be greatly appreciated.
Thanks,
Bryan
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
"Finally, to prevent nasty crashes because the thread hasn’t fully shut down yet when it is deleted, we connect the finished() of the thread (not the worker!) to its own deleteLater() slot. This will cause the thread to be deleted only after it has fully shut down."
Please try replacing:
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));
with:
connect(mp_thread1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));

signal-slot in Qt : emit is located in the slot method

i'm reading a book about Qt, in one of the examples of a signal-slot function, there is the emit method located inside the slot method... So this becomes an infinite loop... i don't really understand how to stop it :
connect(webView, SIGNAL(urlChanged(const QUrl&)),
this, SLOT(urlChange(const QUrl&));
and we then have the function :
void BrowserWindow::urlChange(const QUrl &url)
{
emit urlChanged(url);
progressLabel->setText(tr("Loading"));
}
Thanks
What is webView? (is it the same type?)
The connect is connecting one instance with this slot - its probably not connecting its own instance.
If it was
connect(this, SIGNAL(urlChanged(const QUrl&)),
this, SLOT(urlChange(const QUrl&));
then that would be an infinite loop

Help me understand the QThread usage

I have the MainWindow w windows and TestThread testThread as a member of w. I know it i simple, but I cannot run the testThread.foo() method in testThread thread (not in window thread). In another words: I don't understand the QThread behavior.
Please help correct the next test application. There is a QProgressBar *MainWindow::ui::progressBar and QPushButton *MainWindow::ui::startButton (write simply). I want to start (by startButton click) TestThread::foo(int* progress) which will increment int progress each second.
MainWindow:
MainWindow::MainWindow(QWidget *parent) : // ...
{
// ...
ui->progressBar->setRange(0, 5);
progress = 0; // int MainWindow::progress
this->connect(ui->startButton, SIGNAL(clicked()), SLOT(startFoo()));
connect(this, SIGNAL(startFooSignal(int*)), &testThread, SLOT(foo(int*)));
// TestThread MainWindow::testThread
testThread.start();
}
// ...
void MainWindow::timerEvent(QTimerEvent *event)
{
ui->progressBar->setValue(progress);
}
void MainWindow::startFoo() // this is a MainWindow SLOT
{
startTimer(100);
emit startFooSignal(&progress);
// startFooSignal(int*) is a MainWindows SIGNAL
}
TestThread:
void TestThread::foo(int *progress) // this is a TestThread SLOT
{
for (unsigned i = 0; i < 5; ++i) {
sleep(1);
++*progress; // increment MainWindow::progress
}
}
I know, this is simple. I am doing something wrong :)
P.S. I want to run the simpliest (as possible) example to understand the QThread behavior.
Thanks!
The critical issue is to have the object containing the foo()-function be owned by that thread, so that slot calls are dispatched from the right thread's event-loop.
(Note that there's no need to actually have foo() on the TestThread object. You can use separate objects for QThread and WhatEver::foo() function. It might be easier too, I'm not sure..)
IIUC, this is what you have to do:
Use QObject::moveToThread() to assign the object containing the foo-function to TestThread (that means that Qt::AutoConenction (the default) signal/slots calls will run correctly across thread, being dispatched from each thread's own event loop).
By having the object "owned" by the right thread, slots calls will be scheduled on that thread's event loop, rather than executed directly.
Hope it helps. :)
One alternative solution: If you just want to run a function in another thread, and don't insist using QThread, you should check out the QT Concurrent Namespace.
The following example will run the function foo() in separate thread and will not block on the line where calling the function. Of course there are mechanisms to understand when a function ends, to get a result, to wait for it, to control execution.
void foo(int &progress) {...}
int progress;
QtConcurrent::run(foo, progress);
Hope this helps
See QThread::start and QThread::run.

Resources