I'm trying to implement a multithreaded app that displays video using the OpenCV libraries (following the example given here).
I create two threads from the GUI thread that successfully terminate when the MainWindow is closed. However, the program still keeps on running (I have to use the stop button on the application output panel to close it down).
Here's my destructor for the MainWindow
MainWindow::~MainWindow()
{
captureThread.quit();
converterThread.quit();
if (captureThread.wait())
qDebug() << "Capture Thread has exited successfully";
if (converterThread.wait())
qDebug() << "Converter Thread has exited successfully";
delete ui;
}
The Application Output window returns the following output on both the Debug and Release builds
Capture Thread has exited successfully
Converter Thread has exited successfully
However, the application only quits in Debug mode.
From what I have gathered from a few google searches is that the application continues on running IF there is a thread that has not been properly terminated. Can that be the case here? If yes, then how may I know which other thread is also running in the program, so that I may terminate/quit it?
Using Qt 5.4 with MSVC 2013 and OpenCV 3.0 beta on Win 8.1
Edit
I create my threads in MainWindow constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// registers the type cv::Mat. After a type is registered, one can create/destroy objects at runtime
qRegisterMetaType<Mat>();
// Initializing class' instance
Capture* capture = new Capture;
Converter* converter = new Converter;
ui->labelFrame->setAttribute(Qt::WA_OpaquePaintEvent);
converter->setProcessAll(false);
capture->moveToThread(&captureThread);
converter->moveToThread(&converterThread);
converter->connect(capture, SIGNAL(matReady(Mat)), converter, SLOT(processFrame(Mat)));
this->connect(converter, SIGNAL(imageReady(QImage)), this, SLOT(setImage(QImage)));
// thread clean up
connect(&captureThread, SIGNAL(finished()), &captureThread, SLOT(deleteLater()));
connect(&converterThread, SIGNAL(finished()), &converterThread, SLOT(deleteLater()));
QObject::connect(capture, &Capture::started,
[](){ qDebug() << "capture started"; });
QMetaObject::invokeMethod(capture, "start");
captureThread.start();
converterThread.start();
Edit 2 : I modified my main.cpp to this
QApplication a(argc, argv);
MainWindow w;
w.show();
int ret;
ret = a.exec();
qDebug() << "QApplication.exec() returns " << ret;
return ret;
and I received the following message in the Application output window
QApplication.exec() returns 0
Capture Thread has exited successfully
Converter Thread has exited successfully
which is confusing, since the QApplication should quit after the threads have been stopped. so I moved the thread cleanup to the abouttoQuit() slot. The order of exiting has changed by this modification but the original problem remains. (The wrong order could be due to the implementation of the qDebug() function, but thats just me guessing)
PS I even added captureThread.terminate() and converterThread.terminate() in the destructor but still the results are the same.
Problem
Ok so it turned out to be a memory leak. In the constructor of my MainWindow, I had declared and initialized two instances of converter * and capture * classes. However, when the constructor ended its scope, these pointers were never freed.
Solution
Free the memory in the CleanUp() function. (The CleanUp() function is connected to the aboutToQuit() slot of the application. To make the pointers accessible to the CleanUp() function, declare them as members of the MainWindow class.
QMetaObject::invokeMethod(capture, "start");
Looks suspicious. Can you replace it with:
connect(&captureThread, &QThread::started, capture, &Capture::start);
Also, no need to do thread clean up, because they are members of MainWindow class and will be destroyed with it, remove those two lines:
connect(&captureThread, SIGNAL(finished()), &captureThread, SLOT(deleteLater()));
connect(&converterThread, SIGNAL(finished()), &converterThread, SLOT(deleteLater()));
Related
I need to run a method in my MainWindow class, in a different thread as it is a length and time consuming process.
This is what I tried:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
initGui(ui);
// Create background worker thread
backgroundWorker = QThread::create([this] {
backgroundMethod();
});
// Define when finished with work
connect(backgroundWorker, &QThread::finished, [this] () {
qDebug() << "Background method has finished";
// Stop movie
ui->lblLoading->movie()->stop();
// go to next screen
ui->tabbarMainWidget->tabBar()->setCurrentIndex(1);
//show backup icon files
if(filesToBackup.size() > 0) {
qDebug() << "There are files to backup!";
ui->lblInfoImage->show();
}
});
// Start worker thread
backgroundWorker->start();
}
backgroundMethod
void MainWindow::backgroundMethod() {
for (int i = 0; i < 10; i++) {
qDebug() << "Hello World";
}
}
I am omitting alot of code as it is not necessary. The basic logic is as follows:
Start new thread using QThread::create()
Run the backgroundMethod() until completed while having the UI free for other work.
When the backgroundMethod() has finished, the QThread should emit the finished() signal.
I have a connection setup between the backgroundWorker thread's finished() and the lambda to run some more code.
The problem:
Background method has finished
QObject::killTimer: Timers cannot be stopped from another thread
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 0x0x2801d950. Receiver 'lblInfoImage'
(of type 'QLabel') was created in thread 0x0x2688c4b0", file
kernel\qcoreapplication.cpp, line 578 04:11:28: The program has
unexpectedly finished.
In short, I am accessing the lblInfoImage on the backgroundWorker thread. I understood that using the signal/slot mechanism should cater for this issue, where my use of it is correct.
I am not sure why this is happening, I need some help in understanding what I did to cause the problem and how I can fix it
The problem is simple: you execute UI code on a non-UI thread which is strictly forbidden in Qt (and in many other UI frameworks across different languages). That happens because you do the connection wrong:
connect(backgroundWorker, &QThread::finished, [this] () {
...
});
That connection means: whenever QThread emits a finished signal run this function. The thing is, it will run the function in the context of the emitted signal which is another thread not the thread backgroundWorker lives in. So you have to provide the UI thread context for receiving this signal:
connect(backgroundWorker, &QThread::finished, this, [this] () {
...
});
Now the function provided will be executed in the context of the UI thread (this).
I'm testing a programm on my PI.When running it on the host pc no error is shown, instead , running it on pi (CM3) it freezes.
I'm trying to use multithreading.
From the main thread, in the constructor an QThread is started, then when I click on the button to open a new form the GUI freezes. In the button slot I need to check if the serial_works thread has been started in the constructor has finished before opening a new form, so I added a QThread::isRunning() check;
Main_Form::Main_Form(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Main_Form)
{
ui->setupUi(this);
this->move(0,0);
this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
connect(ui->btn,SIGNAL(clicked(bool)),this,SLOT(open_form()));
*serial_works = new SerialWorks();
serial_works->start();
}
void Main_form::open_form(){
std::cout<<"open form slot"<<std::endl;
int i = 0;
while(serial_works->isRunning()){
std::cout<<"WHILE"<<std::endl;
QThread::msleep(100);
i++;
if(i > 10){
serial_works->terminate();
}
Next_form *frm = new Next_form();
this.close();
frm->show();
}
the run method in the Serial_works class is
void Serial_works::run() {
my_function();
this->terminate();
this->wait();
}
void Serial_works::my_function(){
....stuff on serial
std::cout<<"serial works finished"<<std::endl;
}
on the output i get
//serial works finished
//open_slot_form
no WHILE is printed out on the console,thus the program get stuck on the while check
serial_works->isRunning()
Where is the problem? On the the host pc, the new form opens as expected.
You are trying to use QThread without understanding what is this object doing. What you want to do is asynchronous execution : Do some work and when you are done let me know.
Edit : What is Happening :
Client : main thread executes open_form before the worker executes run
Rasberry Pi : worker executes run before main thread executes open_form
On PI
serial_works->start() launch worker, which execute first, and complete my_function.
worker call this->terminate() and is now officially dead. terminate is a brutal way of stopping a QThread..I cannot even speculate whether wait() is called.
The main thread execute open_form, and the worker is already non-runnable. So the loop is not executed and Next_form is never going to be shown.
Error 1 :
Main_form::open_form()
is executing in the gui thread, and you are sleeping on a event. This is always incorrect. You GUI will freeze for the amout of time you are sleeping. Use signals and slots or events.
Error 2 :
Serial_works is likely a subclass of Qthread. You are confusing a thread of execution with the object managing that thread. You should not subclass QThread.
this->terminate();
this->wait();
The worker thread is executing that code. You are killing yourself then waiting on your death. So depending on the implementation you may wait forever , crash, etc....
What you need to do :
Use QFuture and QFutureWatcher.
//inside Main_Form
QFutureWatcher<ReturnValueType> watcher;
void Main_form::open_form(){
// Instantiate the objects and connect to the finished signal.
connect(&this->watcher, SIGNAL(finished()), &this, SLOT(SignalWorkFinished()));
// Start the computation.
QFuture<ReturnValueType> future = QtConcurrent::run(stuffOnSerialFunction);
this->watcher.setFuture(future);
}
// now handle work finish
void SignalWorkFinished()
{
QFuture<ReturnValueType> future = watcher.future();
//do whatever you like
}
I've a main thread for the GUI, in which is run the MainWindow object,
in its constructor I create a new worker object and a QThread object and the i move the worker to the thread, the problem is that when printing their ids they are the same:
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl;
QThread *t_pc = new QThread;
worker *pc_w;
pc_w = new pc_worker();
pc_w->moveToThread(t_pc);
t_pc->start();
pc_w->initialize();
// ...
}
worker.cpp
worker::worker(QObject *parent) : QObject(parent) {
}
void worker::initialize() {
std::cout << "INITIALIZE " << QThread::currentThreadId() << std::endl;
}
I get:
MAIN_ID 0x7f4009ccb780
INITIALIZE 0x7f4009ccb780
What's wrong?
Answer: moveToThread does work, just not in the way you expected.
Looks like after calling pc_w->moveToThread(t_pc) you expected all member functions of pc_w to be called in t_pc now. However, that is not what moveToThread() does.
The purpose of moveToThread() is to change QObject "thread affinity" or in other words thread where an object lives. But on the basic level everything it gives you is just the guarantee that all the object`s slots connected to any signal via Qt::QueuedConnection will be invoked (run) in that particular thread.
Member functions still run in the thread you invoke them from. In your case, you call initialize() from the GUI thread, so QThread::currentThreadId() gives you the id of that thread.
I really recommend to read official doc on thread affinity and this article on thread event loops.
QThread* thread = new QThread;
Worker* worker = new Worker;
// Uses Qt::AutoConnection (default)
// which will be transalted into Qt::QueuedConnection
QObject::connect(thread, &QThread::started, worker, &Worker::initialize);
std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl;
worker->moveToThread(thread);
thread->start();
Output:
MAIN_ID 0000000000003E5C
INITIALIZE 0000000000003DAC
The solution trivelt proposed artificially puts "call initialize()" event into the thread event loop reaching the same effect. However, it does not perform any compile-time checks ("initialize" is specified as a string).
Try to use invokeMethod instead of diretly calling pc_w->initialize(), e.g.:
QMetaObject::invokeMethod(pc_w, "initialize", Qt::QueuedConnection);
Your initialize() method should be SLOT or SIGNAL in this case.
So I have been stuck at this problem for a while now. For some reason, my application always crashes on close and this is the error message I get:
The inferior stopped because it triggered an exception.
Stopped in thread 0 by: Exception at 0x50c15a08, code: 0xc0000005: read access violation at: 0x0, flags=0x0 (first chance)
The stack shows the following:
QWidget::show Line: 7030
And this is what my main.cpp currently looks like:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I have no clue why the crash is occurring.
A little background: This is a multi-threaded application (using both QThread and QtConcurrent). When the threads are NOT started, the application closes just fine. Hence I added the following check to ensure that the thread is being terminated properly but this is not helping:
void MainWindow::closeEvent(QCloseEvent *event)
{
if (thread->isRunning()) {
thread->terminate();
while(!thread->isFinished()){
}
event->accept();
}
}
EDIT: How the new thread was created
QThread *myThread = new QThread(this);
Worker *worker = new Worker(this, user, p);
worker->moveToThread(myThread);
connect(myThread, SIGNAL(started()), worker, SLOT(doWork()));
connect(worker, SIGNAL(workDone()), this, SLOT(deleteThread()));
myThread->start();
...and this is how I am handling the deletion of the thread after the download completes:
void MainWindow::deleteThread(){
worker->deleteLater();
myThread->quit();
while(!myThread->isFinished()){
}
myThread->deleteLater();
}
You should either listen for terminated signal from the thread or wait for the thread to terminate. Telling the thread to terminate doesn't block, so if you then immediately accept the close event you will get your exception.
This is described in more detail in the documentation for the terminate slot
Proper QThread stop code is:
myThread->quit();
myThread->wait();
Also you have used moveToThread(this);
You need to moveToThread back to parent thread first.
For example your code is:
moveToThread(this);
start();
You need to save currentThread() before moveToThread() like this:
QThread *savedThread=currentThread();
moveToThread(this);
start();
And before quit or terminate you need to restore it:
moveToThread(savedThread);
quit();
wait();
You can put it on destructor of course.
In the example below (inside Qt GUI application) a new thread is started (with an event loop in which I want some work to be done):
void doWork()
{
QThread* workerThread = new QThread();
Worker* worker = new Worker();
worker->moveToThread(workerThread);
connect(workerThread, SIGNAL(started()), worker, SLOT(startWork()));
connect(worker, SIGNAL(finished()), workerThread, SLOT(quit()));
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
workerThread->start();
}
startWork() can be a long running operation during which the application can be closed.
I expected that the application will not be closed as long as startWork() is being executed on the workerThread. It seems though, that when I close the last application window, the workerThread is gone instantaneously (during long running operation) and application closes without problems.
The questions arose:
Why was the workerThread wiped right away?
Is it some parent/child issue?
How Qt handles such situation?
Is it programmer mistake, not to call wait() on QThread (eventually)?
Even if so, I tried to wait() inside a slot for aboutToQuit() and application wasn't closed after long running operation was done (with setup as above). Only quit(); wait(); (inside the slot mentioned) allowed the application to close. Why?
QThread has, basically, a long-standing API bug: it isn't always in a destructible state. In C++, an object is considered to be in destructible state when it's safe to invoke its destructor. Destructing a running QThread is an error. A QThread is merely a thread controller, it's not the "thread" itself. Think of how QFile acts: you can destruct it at any time, whether it's open or not. It truly encapsulates the notion of a file as a resource. A QThread is too thin of a wrapper around the native (system) thread: when you destruct it, it does not terminate nor dispose of the native thread if there is one. This is a resource leak (threads are OS resources), and people trip over this issue over and over again.
When the application's main() function returns, your implementation of the C/C++ runtime library happens to terminate all of the application's threads, effectively terminating the entirety of the application. Whether this is the behavior you desire is up to you. You're supposed to quit() and wait() your event-loop-running thread. For threads without an event loop, quit() is a no-op and you must implement your own quit flag. You must wait() on the thread before you destruct it. This is to prevent race conditions.
Below is a safe wrapper for QThread. It is a final class, since you can't reimplement run. This is important, since a reimplementation of run could be done in such a way that makes quit a no-op, breaking the contract of the class.
#include <QThread>
#include <QPointer>
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { quit(); wait(); }
};
class ThreadQuitter {
public:
typedef QList<QPointer<Thread>> List;
private:
List m_threads;
Q_DISABLE_COPY(ThreadQuitter)
public:
ThreadQuitter() {}
ThreadQuitter(const List & threads) : m_threads(threads) {}
ThreadQuitter(List && threads) : m_threads(std::move(threads)) {}
ThreadQuitter & operator<<(Thread* thread) {
m_threads << thread; return *this;
}
ThreadQuitter & operator<<(Thread& thread) {
m_threads << &thread; return *this;
}
~ThreadQuitter() {
foreach(Thread* thread, m_threads) thread->quit();
}
};
It could be used as follows:
#include <QCoreApplication>
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
QObject worker1, worker2;
Thread thread1, thread2;
// Style 1
ThreadQuitter quitter;
quitter << thread1 << thread2;
// Style 2
ThreadQuitter quitterB(ThreadQuitter::List() << &thread1 << &thread2);
//
worker1.moveToThread(&thread1);
worker2.moveToThread(&thread2);
thread1.start();
thread2.start();
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
return app.exec();
}
Upon return from main, the thread quitter will quit() all worker threads. This allows the threads to wind down in parallel. Then, thread2.~Thread will wait for that thread to finish, then thread1.~Thread will do the same. The threads are now gone, the objects are threadless and can be safely destructed: worker2.~QObject is invoked first, followed by worker1.~QObject.
1) Is it parent / child issue?
Not in the case of your code - You're not parenting the QThread. Qt doesn't like you to just terminate the main thread if you've other threads running. You're likely to see it complain in the standard output that the other thread was still running when the application was terminated. However, Qt will kill the other thread, which is why there's a function to call and wait for the thread to terminate properly.
2) Is it programmer mistake not to call wait()?
Yes. If you're having issues with the Thread not quitting properly, it's because you're not handling it correctly, in which case you could open another question and show the code as to how you're handling the wait before quitting.
when I close the last application window, the workerThread is gone instantaneously
Note that there's a function in QApplication called setQuitOnLastWindowClosed, which you can set to false, to prevent the app automatically quitting on closing the last window.