Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt synchronous method

Tags:

qt

I'm a pure Qt beginner and currently want to understand its basic concepts and how to use them in the right way. My question might appear as somehow "ragged" and I want to apologize for that in advance. This having said, the question is:

I want to implement a method, which "blocks" until the handling is finished (for what reason ever...). In order to do the internals, I have to use an asynchronous class, emmiting a signal when it has finished its job in the background. I want to use that in a blocking way:

QEventLoop myLoop;

workerClass x;

QObject::connect(x, SIGNAL(finished()), &myLoop, SLOT(quit()));

/* x is asnchrounous and will emit "finished" when ist job is done */
x.doTheJob();

myLoop.exec();

Will that work? According to some other postings around - it should. But what is going on exactly?

When a new instance of QEventLoop is just created, does it automatically mean, that signals emitted from myLoop are automatically handled within that new handler? Moreover, the loop starts some while after having started the job. What happens, when it emits already "finished", before myLopp is started?

I have been told by a collegue, that I could use

QEventLoop myLoop;

workerClass x;

QObject::connect(x, SIGNAL(finished()), &myLoop, SLOT(quit()));

/* doTheJob is a slot now */
QMetaObject::invokeMethod(x, "doTheJob", Qt::QueuedConnection);

myLoop.exec();

I understand, that in this case doTheJob is called from the event loop. But from which event loop? invokeMethod() is not told to invoke the method in a particular event loop (myLoop), so why should the event posted to myLoop instead into the "outer" loop? In fact, myLoop is not even running at that time...

I hope I was able to transport my question to be understandable by experts.

Many Thanks, Michael

like image 819
MichaelW Avatar asked Sep 21 '25 05:09

MichaelW


1 Answers

The key is QObject::connect:

QObject::connect(x, SIGNAL(finished()), &myLoop, SLOT(quit()));

This function says when finished() is emitted, myLoop.quit() should be called just after the event occurs. So in your example,

<--------thread A-------->  |  <--------thread B-------->
   QEventLoop myLoop;
   workerClass x;
   x.doTheJob();                 starts thread B
   sleep in exec()               workerClass::JobA();
   sleeping.....                 workerClass::JobB();
   sleeping.....                 workerClass::JobC();
   sleeping.....                 workerClass::JobD();
   sleeping.....                 workerClass::finished();
   sleeping.....       
   wake up by quit();

myLoop.quit must be called after thread A is sleeping, otherwise thread A may sleep forever because quit may be called before sleeping. You have to find a way to specify this. But how? Take a look at QObject::connect, the last argument is

Qt::ConnectionType type = Qt::AutoConnection

And about Qt::AutoConnection,

(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.

The signal is emitted in thread B and the receiver myLoop is in thread A, that means you are using Qt::QueuedConnection:

The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.

The slot myLoop.quit is invoked when control returns to the event loop, myLoop.exec. In other words, quit is invoked only when exec is running. This is exactly what we want and everything works fine. Therefore, your first example always runs correctly because the signal and slot are connecting together using Qt::QueuedConnection (from default value Qt::AutoConnection). Your second example works fine because QObject::connect is the same, too.

If you change it to Qt::DirectConnection, the story is different. quit is called in thread B, it is possible that quit is called before exec and thread A is going to sleep forever. So in this scenario you should never use Qt::DirectConnection.

The story is about QObject::connect and threads. QMetaObject::invokeMethod is not related to this, it simply calls a function when the thread executes an exec function.

like image 113
mcchu Avatar answered Sep 23 '25 12:09

mcchu