|
This is a nice little communication related problem.
I've come across this problem a few times and I've solved it in a similar way each time.
The best suited solution might depend on the protocol you're using, if it's possible to assign an ID to each message that can be used to map the answer to the request.
I assume this is your case.
It also depends on whether the protocol is asynchronous or not, i.e. if you are able to send multiple requests before you get an answer for the first request.
I assume the protocol is synchronous. Correct me if I'm wrong Cédric.
I'm not sure if I can describe how I've done this without a whiteboard, but I'll try...;)
Usually I have a sending thread that reads from a queue that contains reference counting smart pointers to the messages to be sent. All queues mentioned later contains reference counting smart pointers to message objects, even if i refer to them as "messages".
When a message has been sent that requires a reply I put the message into another queue which is read by a thread (the timeout thread) that handles the timeout, but also waits for incoming messages on a semaphore.
A thread that takes care of the message receiving mechanism puts the received messages into the queue read by the timeout thread and releases the semaphore. This will release the timeout thread which is wating on a reply to the front message from the timeout queue and if the message tags/IDs match I've got a reply for the request sent earlier. The other situation is that the timeout expires in the timeout thread which returns from ::WaitForMultipleObjects(...) with the index of the waitable timer that handles the timeout. Perhaps the request message should be re-sent and put into the sending queue again depending on the protocol used.
If the protocol is asynchronous the timeout thread should perhaps have a local container, e.g. a vector, with messages that can be searched for message IDs when a new message arrives. Messages sent should be put at the end of the vector and the waiting is done on the message at the beginning of the vector.
By using this threading and queueing technique you don't risk losing replies if the are immediate, you can even put a message in the timeout queue before sending it.
Each thread is waiting on synchronization objects such as semaphores and waitable timers.
If you have a look at Joe Newcomer's article about semaphores here[^] you should get an idea of how I release the different threads using semaphores when there are new objects in their queues.
N.B. The above requires an integer member in the CMessage class that contains the timeout value in preferably millisecs. The timeout thread creates a waitable timer.
I hope you get what I'm getting at, but let me know if you don't.
--
Roger
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Thanks for your detailed explanation Roger
But I think this will be hard to implement in my application (the design is really different). And also, protocol is totally asynchronous and even, sending messages can be done in different threads.
Anyway, I think I've found a solution. The getReplyBlocking and the setReply functions can be modified in such way:
CMessage* CMessage::getReplyBlocking(unsigned long timeout)
{
WaitForSingleObject(m_hReplyEvent,timeout);
EnterCriticalSection(...);
m_hReplyEvent = NULL;
LeaveCriticalSection(...);
return m_pReply;
}
void CMessage::setReply(CMessage* pReply)
{
EnterCriticalSection(...);
if (m_hReplyEvent)
{
m_pReply = pReply;
SetEvent(hReplyEvent);
}
LeaveCriticalSection(...);
}
The event creation must be done then before sending the message.
Suppose that we call getReplyBlocking and there is a timeout. At this precise time, we receive a message. What could happen: either the message is received just after the WaitForSingleObject (and before we enter the critical section in getReplyBlocking) or we receive the message once we entered the critical section in getReplyBlocking (receiving afterwards is the same scenario).
1) First case: we receive a message at the moment the timeout expired but we didn't enter the critical section in getReplyBlocking, so in setReply we will be able to enter the critical section. The event is still available so we set the reply and we notify it (it will have no impact) then we release the leave the critical section. Then, in getReplyBlocking we enter the critical section, we set the event to NULL and we leave the critical section. The only problem in this situation is that the reply is still set after the timeout expired but honnestly, the times there are largely neglectable.
2) Second case: the message is received when we are already in the critical section of getReplyBlocking. That will force the setReply function to wait until the critical section is left. Then, it will enter its own critical section and check for the reply event. It will be NULL so the reply won't be set.
|
|
|
|
|
Cedric Moonen wrote: Thanks for your detailed explanation Roger
You're most welcome Cédric.
Sorry about the delay but I went out for lunch and I actually had to work for a while...
Just some thoughts, do with them as you please...
Cedric Moonen wrote: And also, protocol is totally asynchronous and even, sending messages can be done in different threads.
Regarding sending from multiple threads I solve this by having a thread that takes care of the sending mechanism as I described earlier. When messages are placed in the send queue it is of course locked with a critical section so multiple threads can "send" messages. After unlocking the queue the corresponding semaphore is released unleashing the send thread that actually transmits the data over the desired carrier.
Regarding the protocol being asynchronous I wonder how you're going to solve it since you're calling CMessage::getReplyBlocking(...) which would block the thread until the timeout expires or a suitable reply is received. During that time you would be unable to send any messages, at least from that thread. This also suggests that you're only sending messages from worker threads since you're not processing windows messages during waiting for replies so you cannot send a message from the main thread that waits for a reply. I sense small warning signs here about the design but it's not alarming.
Regarding the two scenarios at the bottom of your post I consider both of them to be describing a timeout situation for a request. If you discard the message or not makes no difference in my opinion since the message was received too late which usually should be treated the same way as if there was no reply. In this situation perhaps the message should be re-sent depending on the protocol used.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Roger Stoltz wrote: Regarding the protocol being asynchronous I wonder how you're going to solve it since you're calling CMessage::getReplyBlocking(...) which would block the thread until the timeout expires or a suitable reply is received. During that time you would be unable to send any messages, at least from that thread. This also suggests that you're only sending messages from worker threads since you're not processing windows messages during waiting for replies so you cannot send a message from the main thread that waits for a reply. I sense small warning signs here about the design but it's not alarming.
I totally agree. Except that I'm not developing a GUI application at all
It's kind of complicated to explain but I'll try . In fact this application (console application) is spawned by a Java application (and the console window is even not visible because Java will take the stdin and stdout for itself). The application provides a way to access 'parameters' to this java application. And they speak together by using Corba (the stdin and stdout are only used to exchange information about the corba "connectors"). And, if we want to retrieve the value of a parameter in java, the call will go through corba, and will have for effect that a message needs to be sent on a communication link. Thus, you can have several parameter requests issued from different threads.
|
|
|
|
|
Java and Corba?
I dont' envy you one bit.
It may be that I'm not getting exactly what you're trying to do, but I think I understand the big picture.
It feels like you have an external thing that you want to use from the Java app and you're providing the link between the Java app and the external thing.
I hope you have considered a COM component and ruled that solution out because of limitations in the Java app...
There's one thing that I don't get:
In the light of your latest post I interpret your original post to be about the communication between the console app and the external thing. How do you communicate with the console app from the Java app to be forced to have multiple threads in the console app since the console app runs in a process of its own? Or is this a protocol issue from the external thing point of view like keep-alive messages?
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Roger Stoltz wrote: Java and Corba?
I dont' envy you one bit.
In fact I'm not working really on the Java side, mainly on the native side. But I agree, Corba is kind of
Roger Stoltz wrote: I hope you have considered a COM component and ruled that solution out because of limitations in the Java app...
I didn't select the technology but this has to run on several platforms (like Windows CE for example). As far as I understood, COM was not an option for the Java side.
Roger Stoltz wrote: How do you communicate with the console app from the Java app to be forced to have multiple threads in the console app since the console app runs in a process of its own?
Well, the console app is in fact a kind of server that provides parameters that can be used by different clients through a corba connection. So in this way it needs to be multithreaded.
And of course the Java application can also request the same parameter on different threads.
|
|
|
|
|
how to install a package using MFC.
when i execute a mfc program it will install the specified package.
How to do this.plz help me.
|
|
|
|
|
Copy the necessary files, registry properly COM components, etc...
Handly if you have small self-contained C++ applications.
Take also a look to NSIS installation tool, it's free, easy to use,and as they (Nullsoft) say, don't suck.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
|
Interesting but you need to fix the Link.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
Sorry for that. The link worked in my browser when I have posted the comments .
I have been using that software for 3 years and I am satisfied with the results.
|
|
|
|
|
|
|
rotflmao !! this one is excelent
|
|
|
|
|
toxcct wrote: rotflmao !! this one is excelent
I mean, this is the best I could give to someone like him over the internet.
Nobody can give you wiser advice than yourself. - Cicero
ப்ரம்மா
|
|
|
|
|
|
Absolutely wonderful! Hi-5, my-5!
I didn't see the original post, but your reply is priceless.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Roger Stoltz wrote: Absolutely wonderful! Hi-5, my-5!
I didn't see the original post, but your reply is priceless.
Thanks
Original post was "hallo" and the post subject was "dsd". He deserves real slap(s), rather than "Virtual Slaps".
Nobody can give you wiser advice than yourself. - Cicero
ப்ரம்மா
|
|
|
|
|
brahmma wrote: He deserves real slap(s), rather than "Virtual Slaps".
Second that.
But this is the best that can be done until the act of polluting the forum like this is punishable by a fine. A new market for PayPal perhaps...
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Must be checking, if CP forums are working properly.
|
|
|
|
|
prasad_som wrote: He Must be checking, if CP forums are working properly.
Agreed. I just provided a link so that he can understand even hyperlinks work properly in CP.
Nobody can give you wiser advice than yourself. - Cicero
ப்ரம்மா
|
|
|
|
|
|
how to bind groupbox and radiobuttons.or is any container for radiobutton.when i move a container alongwith the radiobuttons also moved
how to perform this.give samples
|
|
|
|
|
I doubt if I get your question properly. Are you asking how to group a few radio buttons together so that only one of them could be selected? For this, you first insert a few radio buttons, go to the first radio button's property, and enable the "Group" checkbox (And uncheck this property for other radio buttons). Now this would for a group of mutually exclusive radio buttons.
PS: The group box is just a visual representation and it won't group the controls together.
Nobody can give you wiser advice than yourself. - Cicero
ப்ரம்மா
|
|
|
|
|
void thread1()<br />
{<br />
do {<br />
....<br />
} while(g_nData == 0);<br />
}<br />
<br />
void thread2()<br />
{<br />
if (g_nData == 1)<br />
{<br />
....<br />
}<br />
}<br />
<br />
void thread3()<br />
{<br />
if (...)<br />
{<br />
InterlockedExchange(&g_nData, 0);<br />
}<br />
else if (...)<br />
{<br />
InterlockedExchange(&g_nData, 1);<br />
}<br />
else<br />
{<br />
InterlockedExchange(&g_nData, 2);<br />
}<br />
}
1. If when thread1() reading g_nData, thread2() write g_nData, whether read first or write first?
2. If when thread2() writing g_nData, thread1() read g_nData, whether wait read done or read first? the g_nData vaule is thread2() write vaule? or old value?
3. If i want keep g_nData write first, how to do?
thanks.
|
|
|
|