How to mix Sockets, Messages and Events - delphi

There is a thread that uses ADO Connection object, operates with a socket(s) and reacts on outer events using WaitForSigleObject or WaitforMultipleObjects. The thread has an endles loop with 3 actions:
While PeekMessage(MSG, 0, 0, PM_REMOVE) do ProcessMessages(MSG); //for processing messages of COM system
if Socket.CanRead then ... //CanRead is true when there is data in socket to read
if WaitForSingleObject(fHandle, 0) = WAIT_OBJECT_0 then ... //fHandle is handle of outer event
Almost all time the thread wastes CPU asking about all three types of events. Is there way to make thread to sleep until one of three types of events happend, like WaitForMultiplyObjects or GetMessage?

It is not clear what kind of library you use for network operations with socket. In general there are two possible ways to work with sockets, blocking or non-blocking sockets. If you use blocking sockets (Indy for example), then probably it is good idea to use separate thread for socket operations.
If you use non-blocking sockets (like ICS library), then you can use MsgWaitForMultipleObjectsEx function for synchronization with flags QS_ALLINPUT for all your input events. You can find more information on this function here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684245%28v=vs.85%29.aspx
Main difference of MsgWaitForMultipleObjectsEx from WaitforMultipleObjects is that first one can wake up not only when some object is signalated, but also when some specific or any message was posted in the queue. Seems it is what you asked.

For the record, ProcessMessages is the single most evil bit of code ever devised. It will create problems the like of which you simply can not imagine.
There are a number of non blocking socket components out there, so you do not have to poll for data FP's ICS comes to mind), perhaps you might want to try that to help with your socket problems.

Related

Asynchronous NSStream I/O with GCD

I am working with an external device that I receive data from. I want to handle its data read/write queue asynchronously, in a thread.
I've got it mostly working: There is a class that simply manages the two streams, using the NSStreamDelegate to respond to incoming data, as well as responding to NSStreamEventHasSpaceAvailable for sending out data that's waiting in a buffer after having failed to be sent earlier.
This class, let's call it SerialIOStream, does not know about threads or GCD queues. Instead, its user, let's call it DeviceCommunicator, uses a GCD queue in which it initializes the SerialIOStream class (which in turn creates and opens the streams, scheduling them in the current runloop):
ioQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(ioQueue, ^{
ioStreams = [[SerialIOStream alloc] initWithPath:[#"/dev/tty.mydevice"]];
[[NSRunLoop currentRunLoop] run];
});
That way, the SerialIOStreams stream:handleEvent: method runs in that GCD queue, apparently.
However, this causes some problems. I believe I run into concurrency issues, up to getting crashes, mainly at the point of feeding pending data to the output stream. There's a critical part in the code where I pass the buffered output data to the stream, then see how much data was actually accepted into the stream, and then removing that part from my buffer:
NSInteger n = self.dataToWrite.length;
if (n > 0 && stream.hasSpaceAvailable) {
NSInteger bytesWritten = [stream write:self.dataToWrite.bytes maxLength:n];
if (bytesWritten > 0) {
[self.dataToWrite replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
}
}
The above code can get called from two places:
From the user (DeviceCommunicator)
From the local stream:handleEvent: method, after being told that there's space in the output stream.
Those may be (well, surely are) running in separate thread, and therefore I need to make sure they do not run concurrently this code.
I thought I'd solve this by using the following code in DeviceCommunicator when sending new data out:
dispatch_async (ioQueue, ^{
[ioStreams writeData:data];
});
(writeData adds the data to dataToWrite, see above, and then runs the above code that sends it to the stream.)
However, that doesn't work, apparently because ioQueue is a concurrent queue, which may decide to use any available thread, and therefore lead to a race condition when writeData get called by the DeviceCommunicator while there's also a call to it from stream:handleEvent:, on separate threads.
So, I guess I am mixing expectations of threads (which I'm a bit more familiar with) into my apparent misunderstandings with GCD queues.
How do I solve this properly?
I could add an NSLock, protecting the writeData method with it, and I believe that would solve the issue in that place. But I am not so sure that that's how GCD is supposed to be used - I get the impression that'd be a cludge.
Shall I rather make a separate class, using its own serial queue, for accessing and modifying the dataToWrite buffer, perhaps?
I am still trying to grasp the patterns that are involved with this. Somehow, it looks like a classic producer / consumer pattern, but on two levels, and I'm not doing this right.
Long story, short: Don't cross the streams! (haha)
NSStream is a RunLoop-based abstraction (which is to say that it intends to do its work cooperatively on an NSRunLoop, an approach which pre-dates GCD). If you're primarily using GCD to support concurrency in the rest of your code, then NSStream is not an ideal choice for doing I/O. GCD provides its own API for managing I/O. See the section entitled "Managing Dispatch I/O" on this page.
If you want to continue to use NSStream, you can either do so by scheduling your NSStreams on the main thread RunLoop or you can start a dedicated background thread, schedule it on a RunLoop over there, and then marshal your data back and forth between that thread and your GCD queues. (...but don't do that; just bite the bullet and use dispatch_io.)

What happens when ShowMessage is called?

I am working on the project where I communicate with another device over COM port.
For incoming data I am using VaComm1RXchar event, there I store the message into the array and increment msgIndex which represents number of messages.
Then I call the function where I work with this message.
Inside this function is this timeout cycle where I wait for this message:
while MsgIndex < 1 do
begin
stop := GetTickCount;
if (stop - start)> timeout then
begin
MessageBox(0, 'Timeout komunikace !', 'Komunikace', MB_OK);
exit(false);
end;
sleep(10);
end;
The strange thing for me is that, when have it like this above then it always end with timeout. But when I put on there before this while cycle a ShowMessage('Waiting') then It works correcly.
Does anyone know what can caused this and how can I solve it? Thanks in advance!
We can deduce that the VaComm1RXchar event is a synchronous event and that by blocking your program in a loop you are preventing the normal message processing that would allow that event to execute.
Showing a modal dialog box, on the other hand, passes message handling to that dialog so the message queue is properly serviced and your Rx events and handled normally.
You can be certain this is the case if this also works (please never write code like this - it's just to prove the point):
while MsgIndex < 1 do begin
stop := GetTickCount;
if (stop - start)> timeout then begin
MessageBox(0, 'Timeout komunikace !', 'Komunikace', MB_OK);
exit(false);
end;
Application.ProcessMessages; // service the message queue so that
sleep(10); // your Rx event can be handled
end;
If there is a lesson here it is that RS-232 communication really needs to be done on a background thread. Most all implementations of "some chars have been received" events lead to dreadful code for the very reason you are discovering. Your main thread needs to be free to process the message that characters have been received but, at the same time, you must have some parallel process that is waiting for those received characters to complete a cogent instruction. There does not exist a sensible solution in an event-driven program to both manage the user interface and the communication port at the same time on one thread.
A set of components like AsyncPro**, for example, wrap this functionality into data packets where synchronous events are used but where the components manage start and end string (or bytes) detection for you on a worker thread. This removes one level of polling from the main thread (ie: you always get an event when a complete data packet has arrived, not a partial one). Alternatively, you can move the communication work to a custom thread and manage this yourself.
In either case, this is only partly a solution, of course, since you still cannot stick to writing long procedural methods in synchronous event handlers that require waiting for com traffic. The second level of polling, which is managing a sequence of complete instructions, will still have you needing to pump the message queue if your single procedure needs to react to a sequence of more than one comport instruction. What you also need to think about is breaking up your long methods into shorter pieces, each in response to specific device messages.
Alternatively, for heavily procedural process automation, it is also often a good idea to move that work to a background thread as well. This way your worker threads can block on synchronization objects (or poll in busy loops for status updates) while they wait for events from hardware. One thread can manage low level comport traffic, parsing and relaying those commands or data packets, while a second thread can manage the higher level process which is handling the sequence of complete comport instructions that make up your larger process. The main thread should primarily only be responsible for marshalling these messages between the workers, not doing any of the waiting itself.
See also : I do not understand what Application.ProcessMessages in Delphi is doing
** VAComm may also support something like this, I don't know. The API and documentation are not publicly available from TMS for ASync32 so you'll need to consult your local documentation.
What happens is that a modal message loop executes when the dialog is showing. That this message loop changes behaviour for you indicates that your communications with the device require the presence of a message loop.
So the solution for you is to service the message queue. A call to Application.ProcessMessages in your loop will do that, but also creates other problems. Like making your UI become re-entrant.
Without knowing more about your program, I cannot offer more detailed advice as to how you should solve this problem.

Hooking into message loop of dbx DataSnap user session

Is there a way to hook into the WndProc of a dbx user session?
Background:
dbx DataSnap uses Indy components for TCP communication. In its simplest form, a DataSnap server is an Indy TCP server accepting connections. When a connection is established, Indy creates a thread for that connection which handles all requests for that connection.
Each of these user connections consume resources. For a server with a couple hundred simultaneous connections, those resources can be expensive. Many of the resources could be pooled, but I don't want to always acquire and release a resource each time it is needed.
Instead, I'd like to implement a idle timer. After a thread finishes with a resource, the timer would start. If the thread accesses the resource before the timer has elapsed, the resource would still be "assigned" to that thread. But if the timer elapses before the next access, the resource would be released back to the pool. The next time the thread needs the resource, another resource would be acquired from the pool.
I haven't found a way to do this. I've tried using SetTimer but my timer callback never fires. I assume this is because Indy's WndProc for the thread isn't dispatching WM_TIMER. I have no control of the "execution loop" for this thread, so I can't easily check to see if an event has been signaled. In fact, none of my code for this thread executes unless the thread is handling a user request. And in fact, I'm wanting code to execute outside of any user request.
Solutions to the original question or suggestions for alternative approaches would be equally appreciated.
We tried to implement something to share resources across user threads using TCP connections (no HTTP transport, so no SessionManager), but ran into all sorts of problems. In the end we abandoned using individual user threads (set LifeCycle := TDSLifeCycle.Server) and created our own FResourcePool and FUserList (both TThreadList) in ServerContainerUnit. It only took 1 day to implement, and it works very well.
Here's a simplified version of what we did:
TResource = class
SomeResource: TSomeType;
UserCount: Integer;
LastSeen: TDateTime;
end;
When a user connects, we check FResourcePool for the TResource the user needs. If it exists, we increment the resource's UserCount property. When the user is done, we decrement the UserCount property and set LastSeen. We have a TTimer that fires every 60 seconds that frees any resource with a UserCount = 0 and LastSeen greater than 60 seconds.
The FUserList is very similar. If a user hasn't been seen for several hours, we assume that their connection was severed (because our client app does an auto-disconnect if the user has been idle for 90 minutes) so we programmatically disconnect the user on the server-side, which also decrements their use of each resource. Of course, this means that we had to create a session variable ourselves (e.g., CreateGUID();) and pass that to the client when they first connect. The client passes the session id back to the server with each request so we know which FUserList record is theirs. Although this is a drawback to not using user threads, it is easily managed.
James L maybe had nailed it. Since Indy thread does not have an message loop, you have to rely in another mechanism - like read-only thread-local properties (like UserCount and / or LastSeem in his' example) - and using main thread of the server to run a TTimer for liberating resources given some rule.
EDIT: another idea is create an common data structure (example below) which is updated each time an thread finishes its' job.
WARNING: coding from mind only... It may not compile... ;-)
Example:
TThreadStatus = (tsDoingMyJob, tsFinished);
TThreadStatusInfo = class
private
fTStatus : TThreadStatus;
fDTFinished : TDateTime;
procedure SetThreadStatus(value: TThreadStatus);
public
property ThreadStatus: TThreadStatus read fTStatus write SetStatus;
property FinishedTime: TDateTime read fDTFinished;
procedure FinishJob ;
procedure DoJob;
end
procedure TThreadStatusInfo.SetThreadStatus(value : TThreadStatus)
begin
fTStatus = value;
case fTStatus of
tsDoingMyJob :
fDTFinished = TDateTime(0);
tsFinished:
fDTFinished = Now;
end;
end;
procedure TThreadStatusInfo.FinishJob;
begin
ThreadStatus := tsFinished;
end;
procedure TThreadStatusInfo.DoJob;
begin
ThreadStatus := tsDoingMyJob;
end;
Put it in a list (any list class you like), and make sure each thread is associated
with a index in that list. Removing items from the list only when you won't use that
number of threads anymore (shrinking the list). Add an item when you create a new thread
(example, you have 4 threads and now you need an 5th, you create a new item on main thread).
Since each thread have an index on the list, you don't need to encapsulate this write (the
calls on T
on a TCriticalSection.
You can read this list without trouble, using an TTimer on main thread to inspect
the status of each thread. Since you have the time of each thread's finishing time
you can calculate timeouts.

How to start a thread into a service in delphi 7, Windows XP?

We need to Start a thread into a service application we developed.
We did in the OnExecute event, and it failed, and later we did in the OnStart event, and it failed again. Maybe we have to do something else to start the thread.
The line of code we only have to type is MonitorThread.Start;
Where and how we can to start the thread??
Thanks.
On the face of it, starting a thread in a service is no different from starting a thread in any other kind of application. Simply instantiate the thread object and let it run. If you created the object in a suspended state, then call Start on it (or, in versions earlier than 2010, Resume).
MonitorThread := TMonitorThread.Create;
MonitorThread.Start; // or MonitorThread.Resume
If that doesn't work, then you need to take a closer look at exactly what doesn't work. Examine exception messages and return codes. Use the debugger to narrow things down.
If it's possible, I advise you to not create the thread suspended. Instead, just provide the object all the parameters it needs in its constructor. Let it initialize itself, and it will start running just before the constructor returns to the caller. No need for additional thread management outside the thread object.

Delphi ScktComp: When is the onWrite event being fired?

I have come to the point of thinking that the onWrite Event of a ClientSocket is redundant when I directly write bytes into the socket connection via SendBuf().
Is my point of thinking somewhere in the desert?
The Delphi Documentation is also somewhat bad because it just sais: "Write a routine for the onWrite event to write into the socket connection."
OnWrite is used when you're using asynchronous IO (when you have ClientType = ctNonBlocking, in other words). It's called when the socket's ready for you to send data.
Thus, your thinking's only half in the desert: if you're using ctBlocking, then don't bother with OnWrite at all. If you need that thread to send data and get on with other stuff at the same time, then use ctNonBlocking and write to the socket in OnWrite.
When you use async sockets, Windows will send your socket a CM_SOCKETMESSAGE, handled by TCustomWinSocket.CMSocketMessage. When that message has its SelectEvent property set to FD_WRITE, the OnWrite's (ultimately) invoked.
The magic ingredient here is the call to WSAAsyncSelect in TCustomWinSocket.DoSetAsyncStyles.

Resources