03-20-2013 08:30 PM
I'm trying to design a small program that involves TCP socket reads and writes. In the help for the ConnectToTCPServer() function, there's a note about the callbackFunction:
The callback function should be short and should return as soon as possible.
My question is, does this statement apply principally to the ConnectToTCPServer() function, or to all callbacks? It seems that once I've called RunUserInterface(), pretty much all my processing will be within callbacks (or routines that the callbacks call).
Am I missing something here?
03-21-2013 10:05 AM
To it's callback function.
03-21-2013 11:47 AM
Generally speaking, that warning applies to all callbacks: a control callback that takes too long to terminate blocks all user input on the user interface. One very common question on this forum is indeed "I have a callback that executes a test but I cannot stop it pressing a stop button because it is unresponsive!" CVI offers ProcessSystemEvents () function exactly to permit processing events in case of a long callback that blocks out other events, but it must be used with cautions: as you can read in the help for the function, Take care when using ProcessSystemEvents, because it can allow other callback functions to execute before it completes.
Additionally, there are several methods to execute code out of a control callback or without blocking the user interface:
In case of a long lasting procedure, I strongly encourage you to handle it in one of these methods instead of running it inside a control callback with embedded calls to ProcessSystemEvents () .
03-21-2013 12:25 PM
Interesting. This raises a different issue: will one callback block another?
I've constructed my program like this:
buttonCB:
{
write a TCP message
wait for newdataFlag
process new data
}
TCPCB
{
read TCP reply
set newdataFlag
}
(newdataFlag is a global variable.)
Is there anything intrinisically wrong with this design? Will the fact that I'm in buttonCB prevent TCPCB from executing?
03-21-2013 02:59 PM
OK, I did a bit of research, and it turns out that my concern is indeed the case. So, I've restructured the program like this:
buttonCB:
{
write a TCP message
}
TCPCB
{
read TCP reply
process new data
}
I'm not thrilled with it, because my TCP callback isn't as brief as I'd like it, but...it works. If I wished to improve on this, which of the options that Roberto recommended above would seem preferable in this application?
Thanks.
03-21-2013 06:49 PM
I have little experience with TCP libary, but according to this page you must process messages in order to receive events in the callback; given this, your rewrite is on the right path. You could have inserted a ProcessSystemEvents inside your loop, but the change in logic is indeed better.
You could make your callback faster by moving processing out of it:
TCPCB
{
read TCP reply
PostDeferredCall (ProcessingRoutine, NULL);
}
03-22-2013 12:02 PM
Hi, Roberto -
I tried the PostDeferredCall(), and it seems to work well. The documentation (ie, the online help) is a bit confusing, though. Am I correct in my understanding that this will not execute until ALL pending callbacks are finished, or merely the TCPCB that posted the deferred call?
03-22-2013 05:40 PM
I am not sure about that. If pending events are lined up in a single queue that is processed when running function has finished, the deferred callback will be executed after already raised events but before others that may happend after PostDeferredCall. This may not be true if events have priority flag associated to them so that they may be processed in an order other than chronological one. I tend to consider the first option is the right one but I am not sure.
Additionally, consider that you may spawn an separate thread to process some events and launch the deferred function in that thread with ProstDeferredCallToThread (): this will definitely alter the order of event processing, especially with multicore PCs
03-23-2013 05:28 PM
I'd like to pursue the issue of callbacks vs. deferred functions a bit more. My application has a "START" button. When the start button is pressed, it's callback sends a message through a socket to a connected device. Upon receiving this message, the connected device sends a block of data to the program (through the same socket). Once the program processes the data, it sends anotherh command for more data, and continues to do so until a "STOP" button is pressed.
I've tentatively designed my program like this:
ButtonCallback:
{
set g_send to true
send a "SEND" command to the device
}
TCPCallback:
{
read the data from the socket
post a deferred call to process the data.
}
ProcessDataCallback:
{
process the data, display, etc.
if (g_send == TRUE)
send another "SEND" command to the device.
}
(let's ignore for now how g_send is set to false)
If my understanding of how callbacks work is correct, TCPCallback and ProcessDataCallback will cause each other to cycle until g_send is set to FALSE.
From my very brief description above, can anyone see a flaw in this design? I welcome any input, but I'm particularly interested in whether a call could somehow be blocked, or fill up and eventually overrun the call stack.
Thank you for any input on this.
03-24-2013 06:23 AM
I see no real flaw in this design: the deferred callback is fired by TCP callback after receiving a complete message and fires a new message to the device only after terminating handling data.
This structure stresses the system (intended as external device and PC application) to the maximum possible throughput, in the sense that each step is executed immediately after the preceding one is completed, without any pause or delay.