PDA

View Full Version : How to ensure threads run() function executes first



nitks.abhinav
24th November 2017, 19:21
Hi ,

I have the below code where I am using threads **started signal** to ensure run function of the clientThread executes first and then any other function. All initialization are done in the run function and if any other function (serverConnect fn as below) executes first it creates issues.
But using logs I see that 1 in 10 times run function of clientThread executes after serverConnect().

Thank you,



void Base::drpThreadStarted()
{
/* Once DRP thread is started , start the client thread. */
connect(clientThread,SIGNAL(started()),this,SLOT(c lientThreadStarted()));
clientThread->start();
}


void Base::clientThreadStarted()
{
/* Connect to the notification server. */
clientThread->serverConnect();

/* Connect to the message queue in watchdog. */
clientThread->watchdogConnect();

}

high_flyer
24th November 2017, 21:59
But using logs I see that 1 in 10 times run function of clientThread executes after serverConnect().

That doesn't have to mean this is the real order of things, rather, that is the order of when the log messages were logged, which is very different, and you have to consider this possibility in a threaded environment.
Just for sake of testing, you can set a flag in your QThread::run() method, and read it back in Base::clientThreadStarted() - see if the flag is ever not set when clientThreadStarted() runs.

nitks.abhinav
29th November 2017, 18:43
Got it resolved, Thanks.

high_flyer
6th December 2017, 21:25
Got it resolved, Thanks.


Would be nice if you could share how, so others reading the thread later with a similar problem could benefit as well.

nitks.abhinav
14th December 2017, 21:35
I modified the run function to include a single shot timer, the timeout Signal is connected to Slot function which will call the connect functions:


void ClientThread::run()
{

/*Initialize the connect to servers timer*/
conn_to_server_timer = new QTimer;
connect(conn_to_server_timer, SIGNAL(timeout()), this, SLOT(clientThreadStarted()), Qt::QueuedConnection);
conn_to_server_timer->setInterval(100);
conn_to_server_timer->setSingleShot(TRUE);
conn_to_server_timer->start(); // puts one event in the threads event queue

exec(); // puts the thread in event loop
}

void ClientThread::clientThreadStarted()
{
/* Connect to the notification server. */
serverConnect();

/* Connect to the message queue in watchdog. */
watchdogConnect();
}

high_flyer
15th December 2017, 12:21
This is not really a solution, its a hack, which happens to work for you on the specific setup you have.
There is no guarantee that on another system, the interval you set will be sufficient.
Since you have't posted any relevant code (I assume the run() you posted is not complete, as only putting the connect statements in a thread makes little sense) , I can't offer a better solution.

nitks.abhinav
15th December 2017, 21:25
what I understand from how QT works, the exec() function of the QT puts the thread into event loop and then only thread starts processing all events, also timeout event of "conn_to_server_timer" timer.
So even if timer times out before exec() function, slot function will only be executed by exec(). Also my goal was to make sure connect to server happens after run().
I don't think its a hack, its just the serialization.

high_flyer
17th December 2017, 00:51
what I understand from how QT works, the exec() function of the QT puts the thread into event loop and then only thread starts processing all events,
The exec() you call within QThread::run() starts the threads own event loop - it NOT the applications event loop.


So even if timer times out before exec() function, slot function will only be executed by exec().
Hmm...
I'd ask for a second opinion on this.
I am not sure, but if exec() starts the event loop, and the timer fires before the event loop started, where will this event go? the event loop did not start yet.
It could be that even if the event loop is not running it will queue events (but not process them) but I never checked it - you might want to check it.


Also my goal was to make sure connect to server happens after run().
After run() has existed, or after run() has been called (but not necessarily finished)?
If its the former, then you could simply connect to the finished() signal of the thread.
It its the later, simply send a signal from run() and connect to it.

If run is only doing initialization, you could pack it in is own class, and move that object to the thread - without the need to subclass QThread - from a design perspective its a better approach.


I don't think its a hack, its just the serialization.

Anything relaying on an arbitrary timeout to execute "in the right order" in a threaded environment - is a hack.

nitks.abhinav
18th December 2017, 15:15
The only valid concern I can see is "if exec() starts the event loop, and the timer fires before the event loop started, where will this event go? the event loop did not start yet".

Ok you mean to say just after initialization of members, I can emit a signal and in the handler I can connect to the servers? Also I don't want anything to do on thread exit, so do not need finished signal.

high_flyer
18th December 2017, 15:40
Ok you mean to say just after initialization of members, I can emit a signal and in the handler I can connect to the servers?
Well yes, which at the end is exatcly what should have been connecting to the QThread::started() signal.


Also I don't want anything to do on thread exit, so do not need finished signal.
From the code you posted it does seem that way though since you have no other code in your run().

To be frank, for me at least you posted to little information and too little code to know where or even what the problem is.
You have to remember, that what yo are talking about in terms of what you see as behavior, is not the problem, but the symptom.
To understand the problem, more code is needed, especially when we talk about a threaded setup.

nitks.abhinav
18th December 2017, 15:52
I very well know and wish I could post more code , but because of some constraints I cannot.

Anyways, Thank you for help!