PDA

View Full Version : regarding Qt::BlockingQueuedConnection



sattu
14th March 2013, 12:05
Hi everyone,
Let me explain my problem through an example. I have 2 different classes both running in different threads.


A.h (header file)
Class A
{
public:
A();
signals:
void sigA();
private slots:
void slotA();
}

A.cpp (source file)
A::A()
{
emit sigA();
}
void A::slotA()
{
//some processing
}

B.h
Class B
{
signals:
void sigB();
private slots:
void slotB();
}

B.cpp
void B::slotB()
{
emit sigB();
}

main.cpp
void main()
{
A objA;
B objB;
QObject::connect(&objA, SIGNAL(sigA()), &objB, SLOT(slotB()), Qt::BlockingQueuedConnection);
QObject::connect(&objB, SIGNAL(sigB()), &objA, SLOT(slotA()), Qt::BlockingQueuedConnection);
}


In short I am emitting sigA which is connected with slotB. From slotB I am emitting sigB which is connected with slotA. And both the connections are in BlockingQueuedConnection mode. As a result the application is going into deadlock when the following step is executed :-

emit sigB();.
If I remove Qt::BlockingQueuedConnection from the connection between sigB and slotA then it's fine. But I want both to be in BlockingQueuedConnection i.e I want sigA to hang/wait until slotA hasn't finished executing. Can anyone explain me why deadlock is happening and how to achieve the same without causing deadlock? :confused:


-With regards,
sattu

Lesiok
14th March 2013, 12:29
From QObject doc : Same as QueuedConnection, except the current thread blocks until the slot returns. This connection type should only be used where the emitter and receiver are in different threads. Note: Violating this rule can cause your application to deadlock. You are emmitting signal to thread which is blocked so You have what You do.
Maybe You should use QuedConnection and synchronise threads with mutex ?

wysota
14th March 2013, 12:32
Why do you think you need a blocking queued connection?

sattu
14th March 2013, 13:16
From QObject doc : Same as QueuedConnection, except the current thread blocks until the slot returns. This connection type should only be used where the emitter and receiver are in different threads. Note: Violating this rule can cause your application to deadlock. You are emmitting signal to thread which is blocked so You have what You do.
Great, since I am emitting signal to a thread which already is blocked so it results in a deadlock. Understood, :)

Maybe You should use QuedConnection and synchronise threads with mutex ?
Well, my whole purpose is that sigA should wait until slotA has finished executing. But the problem is slotA is called when sigB is emitted from slotB. I will look into QuedConnection but I am not sure how mutex may help me in this case.


Why do you think you need a blocking queued connection?
If i want a signal to wait until the connected slot is finished executing, then I should use blocking connection, right?

MarekR22
14th March 2013, 14:15
The whole concept of signal and slot is "fire and forget". Qt::BlockingQueuedConnection is just spatial case needed only when slot should return some value (for example in some cases of DBus usage). When you don't send data back from slot to signal then use of BlockingQueuedConnection is redundant.

QueuedConnection works like that: Qt packages signal parameters and send it as event to event loop respective to the receivers thread. When event loop of that thread gains control, parameters are unpacked and proper slot is called. Event loop HAS TO gain control to make things happen.
Difference in case of BlockingQueuedConnection is that signal doesn't return (blocks) until it revives information that all slots has processed signal (control returns to event loop), so if you are sending back a signal also with BlockingQueuedConnection then you have a dead lock. Both signals are waiting until other tread returns control to respective event loop.

wysota
14th March 2013, 14:27
If i want a signal to wait until the connected slot is finished executing, then I should use blocking connection, right?
I'm asking you why you want to wait.

sattu
14th March 2013, 16:13
The whole concept of signal and slot is "fire and forget". Qt::BlockingQueuedConnection is just spatial case needed only when slot should return some value (for example in some cases of DBus usage). When you don't send data back from slot to signal then use of BlockingQueuedConnection is redundant.
Correct. But when I need to know in sender thread whether slot(in receiver thread) has finished executing or not, then the only option is BlockingQueuedConnection, right? Yes, the slot is not returning any value, but at the same time signal should wait until the connected slot has finished executing. So, is there any other alternative for such scenarios?

Added after 37 minutes:


I'm asking you why you want to wait.
Well, the scenario is little bit complex but still I will try to explain.
SCENARIO-- I have a sensor thread and a tcp-client thread. Whenever sensor captures some biometric data, it will send the captured data to the tcp-client thread. The tcp-client will in turn send the biometric information to a remote authentication server which will respond with a "yes" or "no". When the tcp-client thread(which is waiting for the remote server's response) gets the response from server, it will immediately relay it back to the sensor thread. So, I require 2 pairs of signal-slot connection. One for sensor-to-tcpclient and another for the reverse.
PROBLEM-- But until tcp-client hasn't replied with the authentication response, sensor thread should wait. This is where my confusion begins :confused:.
MY APPROACH-- Since using of 2 BlockingQueued Connection was out of question, so I solved it temporarily by using a boolean variable in my sensor class i.e once I have sent the data to the tcpclient class the variable becomes true and it won't become false until the time I haven't got the response back from tcpclient.

But I am sure there must be a much better way to achieve the same. Like just now I saw that there is a method in tcpclient class which is :-
waitForReadyRead ( int msecs ).
Sorry for taking such a long time to reply but all the way I was thinking how to reply in a very short and precise way :D

Added after 8 minutes:

Or maybe instead of taking a separate thread for tcpclient, I can directly declare it's object in my sensor class and connect it's readyread() signal with a slot of sensor class. So after doing

objClient->write(sendData);
I can call
objClient->waitForReadyRead(); which will cause my sensor thread to hang until I haven't received response from server. Once I have received the data my readyreadslot() will immediately be called and I can get the response in the sensor class only.

lanz
15th March 2013, 05:38
You can use states, say your sensor thread has two states: idle and data processing.
Whenever sensor thread is in idle state it waits for biometric data to be input, then when it acquires it it sends it to client and changes state to data processing.
So now it can respond to further events (say gui updates, or user cancel event, etc)
Meanwhile tcp client does authentication, and after it completes it send nonblocking signal with the result to the sensor thread.
The sensor thread then do what it need to do with the result and switching back to idle state.

wysota
15th March 2013, 06:42
I say scrap all the threads and use regular signals and slots. If I ever hear "networking thread" or "tcp thread" again I think I might explode.

sattu
15th March 2013, 11:49
I say scrap all the threads and use regular signals and slots. If I ever hear "networking thread" or "tcp thread" again I think I might explode.
Okies, sure sure :). Now I am confused why in the first case I even thought of using 2 pairs of signal-slots, that too both in blocking mode. My bad :confused:. Thanks once again,

anda_skoa
17th March 2013, 15:00
It is not your fault, a lot of frameworks require setups like this.

As lanz indicated one alternative is to describe the states your program can be in and then just to event based processing.
Can be done in a separate thread but might not be necessary. This mainly depends whether you can read from the sensor in a non-blocking way.

Cheers,
_

sattu
18th March 2013, 08:38
Thanks a lot anda_skoa. Discussing here I got a lot of clarifications. As Wysota said I don't even need to implement a separate thread. It works fine without it :).

jboban
3rd April 2013, 16:36
If I ever hear "networking thread" or "tcp thread" again I think I might explode.
Absolutely right! Many people think that must wait for TCP/Network work or slows down his programs. Instead, TCP is buffer and you don't have to waste the time waiting on it. Just write to it, and let event loop runs.

P.S. I'v solved my problem by reorganizing protocol. Thanks. ;)

sattu
4th April 2013, 05:55
Absolutely right! Many people think that must wait for TCP/Network work or slows down his programs. Instead, TCP is buffer and you don't have to waste the time waiting on it. Just write to it, and let event loop runs.

You should not reply without properly understanding the post. Anyone working in the domain of socket programming knows that TCP is a buffer and you don't have to wait after writing the data. And that's the exact reason why you have 2 different approach to TCP programming- synchronous and asynchronous. But in some cases you need to wait for the response after writing data to the socket. And my post was regarding those "some cases". And I definitely am not "wasting my time waiting for the response" because that's what the requirement is. Send a request to SERVER and wait for it's response.

wysota
4th April 2013, 07:12
Anyone working in the domain of socket programming knows that TCP is a buffer and you don't have to wait after writing the data.
Anyone working in the domain of socket programming should also know the buffer is limited and can be filled completely when there is congestion in the network which can block your application for an indefinite amount of time.


But in some cases you need to wait for the response after writing data to the socket.
I don't think that's the case. If you decide to wait then that's your choice but you certainly don't need to wait. You can happily do other things while the data is not there and come back to where you left off when data arrives. Logically you'll still be "waiting for data" but physically you will have those resources available for other tasks. This is safer in terms of both security and durability.

sattu
4th April 2013, 07:48
If you decide to wait then that's your choice but you certainly don't need to wait. You can happily do other things while the data is not there and come back to where you left off when data arrives. Logically you'll still be "waiting for data" but physically you will have those resources available for other tasks. This is safer in terms of both security and durability.

Yes Sir, but in my case it's about requirement, not choice. And my requirement is such that application should not do anything until data/response is received from server. Mine is an "Authentication" model. Client should wait until either server authenticates or timeout happens. So all this stuff :)

wysota
4th April 2013, 08:17
Yes Sir, but in my case it's about requirement, not choice. And my requirement is such that application should not do anything until data/response is received from server. Mine is an "Authentication" model. Client should wait until either server authenticates or timeout happens. So all this stuff :)

"Not do anything" and "wait" are two different things. If You choose to "not do anything" by waiting then that's your choice but it is not the only (and most probably not the most farsighted) approach. What if you want to cancel authentication? What if you need to authenticate against more than one entity at the same time? You can't do any of those with a blocking approach.

sattu
4th April 2013, 09:46
What if you want to cancel authentication?
I can't because I am using a state parameter to disable all the keypress events until authentication completes or timeout happens. I mean I don't want the user to navigate to any other screen until authentication happens. But yes, I never thought of this question before. If I have to add "cancellation" part then I have to refine the code further or maybe change it altogether. As I told my intention here is not to allow the user to change the screen (even if by mistake) until the process is completed.

What if you need to authenticate against more than one entity at the same time?
This should not be a problem because basically my application is not hanging. Only the Keypress part is disabled till completion of process.

You can't do any of those with a blocking approach.
Nooooooooooooooooo. I am not using blocking approach :D. I am using a state variable for maintaining the status but application is free to process anything that may be required during this "waiting" time.

wysota
4th April 2013, 10:08
As I told my intention here is not to allow the user to change the screen (even if by mistake) until the process is completed.
This is usually done either by disabling the UI or by opening a "please wait" modal dialog on top of it. If you block the UI then for example windows will not be redrawn and you'll be getting ugly gray rectangles on your UI.


This should not be a problem because basically my application is not hanging.
If you make blocking calls to the socket (or whatever else that blocks, e.g. BlockingQueuedConnection) then your application is hanging.


I am not using blocking approach :D. I am using a state variable for maintaining the status but application is free to process anything that may be required during this "waiting" time.
So why the heck did you write this and cause confusion:

But in some cases you need to wait for the response after writing data to the socket
jboban's statement was perfectly fine so why did you start arguing with it?

sattu
4th April 2013, 10:36
If you make blocking calls to the socket (or whatever else that blocks, e.g. BlockingQueuedConnection) then your application is hanging.
So why the heck did you write this and cause confusion:
Don't know what to say. Whether or not to use "BlockingQueuedConnection" was my doubt. That's why I named my topic like that. But then as Lanz suggested, I can instead go for the use of states and you also replied that "separate threads are not at all necessary". And that's what I am doing now. I am not creating any confusion. The post was regarding my doubt (i.e BlockingQueuedConnection) and the conclusion was that there are better alternative approaches for it. So I wrote "I am not using blocking approach" (because this topic got solved a long time back).


jboban's statement was perfectly fine so why did you start arguing with it?
Yaa correct, his statement was PERFECTLY fine. My mistake, leave it.