c++ - Qt connection type between threads: why does this work? -
while trying make multi-camera system work different thread handling different camera, couldn't signals , slots working correctly between different threads. knew wrong fact object sending signal , related slot's object living in different threads, , knew had find appropriate "connection type" parameter connection. eventually, ended discovering using qt::directconnection make work should.
find simplified code below. here's small description of how should work.
application main program supposed create threads , start them. in simplified version, waits worker finish jobs through slot "quit".
worker object performs 1 of threaded tasks. in simplified example, wait time before finishing computation. worker emits signal directed application instance, allowed wait threads , quit qcoreapplication.
what finding if don't use qt::directconnection in second connect, finished() signal of worker not trigger quit() slot of thread, means application remains hanging waiting thread.
my question is: why so? since 2 objects (the worker , thread) belong different threads, shouldn't using queuedconnection, or else? thought directconnection should used objects belonging same thread.
main.cpp:
#include <iostream> #include <qcoreapplication> #include "program.h" using namespace std; int main(int argc, char **argv) { qcoreapplication app(argc, argv); program *p = new program; p->execute(); app.exec(); delete p; }
program.h
#ifndef _program_h_ #define _program_h_ #include <qthread> #include <qtimer> #include "worker.h" class program: public qobject { q_object private: worker *worker; qthread *thread; public: void execute(); public slots: void quit(); }; #endif // _program_h_
program.cpp
#include "worker.h" using namespace std; void program::execute() { worker = new worker(); thread = new qthread; worker->movetothread(thread); cout << "connection established: " << connect(thread, signal(started()), worker, slot(process())) << endl; // slot not called if remove fifth parameter // or if put qt::queuedconnection cout << "connection established: " << connect(worker, signal(finished()), thread, slot(quit()), qt::directconnection) << endl; cout << "connection established: " << connect(worker, signal(finished()), this, slot(quit())) << endl; cout << "connection established: " << connect(worker, signal(finished()), worker, slot(deletelater())) << endl; cout << "connection established: " << connect(worker, signal(finished()), thread, slot(deletelater())) << endl; thread->start(); } void program::quit() { cout << "waiting.." << endl; thread->wait(); cout << " .. i'm done!" << endl; cout << "quitting all.." << endl; qcoreapplication::quit(); cout << " .. i'm done!" << endl; } #include "program_moc.cpp"
worker.h
#ifndef _worker_h_ #define _worker_h_ #include <qobject> class worker: public qobject { q_object public slots: void process(); signals: void finished(); }; #endif // _worker_h_
worker.cpp:
#include <iostream> #include <unistd.h> #include "worker.h" using namespace std; void worker::process() { cout << "worker::process() started" << endl; usleep(1000000); cout << "worker::finished() being emitted" << endl; emit finished(); cout << "worker::process() finished" << endl; } #include "worker_moc.cpp"
edit
following @ariwez 's answer solve problem in specific simplified example, doesn't in more complex one, adding now.
in example,
program has own job execute periodically through use of qtimer. program has yet qtimer used simulate user quitting program, triggers execution of slot program::quit().
worker executes own job until quitting flag gets set false. done inside program::quit().
as in previous example, worker finishes procedure , emits finished() signal, supposed connected thread's quit() slot. however, somehow slot must not executed, because program hangs waiting thread. differently previous example, relocating movetothread procedure not solve issue: works if , if use qt::directconnection type connection between worker::finished() , qthread::quit(), , can't understand why.
main.cpp: same above
program.h:
#ifndef _program_h_ #define _program_h_ #include <qthread> #include <qtimer> #include "worker.h" class program: public qobject { q_object private: qtimer *timer, *quittingtimer; worker *worker; qthread *thread; public: ~program(); void execute(); private slots: void quit(); void update(); }; #endif // _program_h_
program.cpp:
#include <iostream> #include <qcoreapplication> #include "program.h" #include "worker.h" using namespace std; program::~program() { delete timer; delete quittingtimer; } void program::execute() { timer = new qtimer(); timer->setinterval(500); connect(timer, signal(timeout()), this, slot(update())); worker = new worker; thread = new qthread; cout << "connection established: " << connect(thread, signal(started()), worker, slot(process())) << endl; // doesn't work if remove qt::directconnection cout << "connection established: " << connect(worker, signal(finished()), thread, slot(quit()), qt::directconnection) << endl; cout << "connection established: " << connect(worker, signal(finished()), this, slot(quit())) << endl; cout << "connection established: " << connect(worker, signal(finished()), worker, slot(deletelater())) << endl; cout << "connection established: " << connect(worker, signal(finished()), thread, slot(deletelater())) << endl; worker->movetothread(thread); timer->start(); thread->start(); // simulates user pressing key close program quittingtimer = new qtimer(); quittingtimer->singleshot(4000, this, slot(quit())); } void program::quit() { cout << "timer->stop()" << endl; timer->stop(); cout << "worker->quit()" << endl; worker->quit(); cout << "thread->wait()" << endl; thread->wait(); cout << "qcore->quit()" << endl; qcoreapplication::quit(); } void program::update() { cout << "program::update() called" << endl; } #include "program_moc.cpp"
worker.h:
#ifndef _worker_h_ #define _worker_h_ #include <qobject> class worker: public qobject { q_object private: bool quit_flag; public: void quit(); public slots: void process(); signals: void finished(); }; #endif // _worker_h_
worker.cpp:
#include <iostream> #include <unistd.h> #include <qthread> #include "worker.h" using namespace std; void worker::quit() { quit_flag = true; } void worker::process() { quit_flag = false; while(!quit_flag) { cout << "worker::process() processing" << endl; usleep(300000); } cout << "worker::finished() being sent" << endl; emit finished(); cout << "worker::finished() sent" << endl; } #include "worker_moc.cpp"
edit 2
re-reading article in @ariwez 's link found out problem in second example. problem main event loop being interrupted, while waiting thread's qthread::finished() signal, , worker::finished() signal not dispatched qthread::quit() slot. yeah, deadlocked myself.
you movetothread before connects that's why in 1 thread.
Comments
Post a Comment