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.
Related
I'm using Delphi XE in order to create a multi thread application.
I want to create a thread to handle all the writing into a firebird/sqlite database log.
And i want to create several threads that do some jobs and these other threads need to use the writing log thread when they need.
Thread1 = writing log thread
Thread2 = do some math and from time to time use Thread1 to write log.
Thread3 = do some other stuff and from time to time use Thread1 to write log.
and so on
for simplicity I have created a method in thread1 named WriteCollectionLog that all the other thread need to use to write the log into thread1 memory (a collection) and thread1 "onexecute" will handle the real log write into the database. This method is intended to be used like a "fire and forget" method.
now how do i make this thread safe? or can I make it thread safe? (by using TCriticalSection?)
thread2.WriteCollectionLog ...
thread3.WriteCollectionLog ...
procedure Thread1.WriteCollectionLog(aIDWORKFLOW : Integer);
var workItem : TLogFIREBIRD_Item;
begin
try
readWriteCriticalSection.Acquire; <--- this will suspend the calling thread .. like thread2, thread3 and not the thread1?
do stuff;
finally
readWriteCriticalSection.Release;
end;
end;
Regards
Razvan
Just implement what you wrote: only write to the DB from Thread1.
Please don't expect to "call" one thread from another, as you may using "Synchronize" to run some code in the main thread. It would be blocking, which is not what you expect, I guess.
The idea is to have a small in-memory structure, shared between the threads, protected by a critical section. One goal is to keep any critical section as small as possible.
For instance, you may use a TObjectQueue, then Thread2 and Thread3 will push some data to the queue, and Thread1 will wait for some pending data in the Queue, then unqueue it and write it - and if you define a transaction, it will be faster than a naive blocking process. If you just want to write some log content, use a TArray<string>, with an associated lock.
I have an application that can send a message to another application. Under pre-Win8 systems, that works fine. You give it the class or title, it uses enumwindows and finds the target window. With Win8, you can only enumerate top level windows, which means the TApplication class. The sending side is happy with that, but the receiver isn't.
To catch the message I'm using this code within my target form ...
function Tmain.AppMsgHookFunc(var wmsg : TMessage) : Boolean;
begin
Result := False;
if wmsg.Msg = WM_COPYDATA then begin
// Post the caught message back to this form.
postmessage (handle,wmsg.Msg,wmsg.WParam,wmsg.LParam);
end;
end;
... and then activate this with application.hookmainwindow etc.
This never fires. I see that if I use sendmessage to send myself the message then it does fire, but if I use postmessage that doesn't work, even on XP. Any suggestions?
WM_COPYDATA is a sent message. The system marshals data cross-process. In order to do so, the system must know that the message has been processed in order to be able to tidy up the resources used to make the cross-process marshalling happen. And the way that the system knows that the message has been processed is by forcing you to send it synchronously. That means you must use SendMessage rather than PostMessage.
The documentation also contains this information, although you do need to know how to interpret it.
An application sends the WM_COPYDATA message to pass data to another application.
Note the use of the word "sends". That is code for the message being synchronous.
Raymond Chen discusses this issue here: Why can't I PostMessage the WM_COPYDATA message, but I can SendMessageTimeout it with a tiny timeout?
The important difference from the standpoint of messages like
WM_COPYDATA is that with sent messages, the window manager knows when
message processing is complete: When the window procedure returns. At
that time, it can free the temporary buffers used to marshal the
message from the sender to the recipient. If the message were posted,
the window manager would never be sure.
Suppose the message is placed in a MSG structure as the result of a
call to GetMessage. Now the window manager knows that the receiving
thread has the potential for taking action on the message and the
buffers need to be valid. But how would it know when the buffers can
be freed? "Well you can wait until the exact same parameters get
passed in a MSG structure to the DispatchMessage function." But what
if the message loop discards the message? Or what if it decides to
dispatch it twice? Or what if it decides to smuggle it inside another
message?
Posted messages have no guarantee of delivery nor do they provide any
information as to when the message has been definitely processed, or
even if it has been processed at all. If the window manager let you
post a WM_COPYDATA message, it would have to use its psychic powers
to know when the memory can be freed.
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.
I must process a very long database table an think of the most common way to abort this loop. The principal code sequence goes like this
procedure TForm.ProcessmyTable(Sender : TObject);
begin
.....
myTable.first;
repeat
ReadSingleRecordfromTable ( MyTable, aRecord) ;
ProcessMyRecord(aRecord) ;
MyTable.next;
until MYTable.EOF;
end;
unit .... ;
procedure ProcessMyRecord(aRecord : TMyDataRecord) ;
begin
// do not have user interface stuff here
// Application.Processmessages will not work here !!!
.... ( long running code sequence)
end;
Could do a timer and break the loop based on the timer with var as a flag support .... but is this really the most clever way of solving this issue?
If this code runs in the main thread, then you will need to service the message queue (i.e. call Application.ProcessMessages) if you want the user to interact with your program and abort. In which case I think you already know the solution. Call Application.ProcessMessages. If the user chooses to abort, set a boolean flag and check that flag regularly in the inner-most loop.
Of course, this is all rather messy. The fundamental problem is that you are performing long-running actions on the GUI thread. That's something you should not do. Move the database processing code onto a different thread. If the user chooses to abort, signal to the thread that it is to abort. For example a call to the Terminate method of the thread would be one way to do this.
When do you want to abort? If it takes too long of if the user says 'stop'?
In both cases change your
until MYTable.EOF;
to
until MYTable.EOF or Aborted;
then set your Aborted boolean either when the timer triggers or when the user presses a key (note that you then have to use Application.ProcessMessages in the loop for the program to be able to process the keypress). This will not abort in your processing routine but after each record. If that is not fast enough you will have to show your record processing routine.
If it's such a long process that the user might want to abort surely in a windows app there should be some interaction with the GUI, a count of records done or a progress bar (if not on every record then on a periodic basis) any call to update a label or progressbar will provide the opportunity to set an abort flag (so processmessages is not required). Plus if the user can see some progress they may be less likely to abort when bored but 95% complete.
IMHO :)
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.