Move the function to a separate worker thread where there are no async events.
Async event in main thread should post some message into some queue, so when the worker thread complete execution, the main thread would start it once again with new parameters.
There was update with some more info.
Assuming (guessing) that the functions works over received data over RS232 or over nothing, and is doing something like GUI update, i'd sketch the following approach.
- use Windows messaging queue of the form for alerting.
- use some interlocked queue objects for data passing. (yes, i know i can put pointers into Windows message, but i'd like a bit more type safety)
- use external working thread for long processing.
More details:
- grep VCL sources for WM_USER and see the pattern. You declare 3 message id constants: Work_Complete, Work_Request, Work_EmptyQueue. And correspondent message-methods in form.
- I'd use ready thread-safe queue from OmniThreadLibrary. But you may subclass System.Contnrs.TQueue or System.Generics.Collections.TQueue, wrapping making all their data-passing methods into critical section. Overall i suggest you to loo at OmniThreadLibrary pipelines if they can suite you
- that is standard way of hardware data working apps. Be it MS-DOS device drivers. Or some embedded device. You should separate fast and lean data saving from long working.
So, the RS232 event handler would read data from COM, put it into TBytes, and then add that packet to input TQueue. A bit more complex approach would be to look if Queue already contains data from COM and aggregating new packet with old rather than patting new packet as separate. That would require more careful locking, so aggregating here maybe just does not worth the candles
Timer even would make empty packet (zero-length bytes array) and enqueue it similarly. if that timer even also has some data to pass - then it should be variant record or separate input queue or whatever. But without information it seems timer just sends no info but the alert itself
According to your words both Timer and RS232 events work in their separate threads. I have doubts about that but i have to trust you.
After enqueuing the workload (for example in the input queue's notify event) i'd do win32 PostMessage(MainForm.Handle, work_request). Afterall we'd like to centralize threads control in one place. To keep threads isolated message should be posted, no SendMessage no TControl.Perform!
In main thread in the form's work_request handler i'd look if the input queue is not empty already. If not, then i'd look at the worker thread state. If it is suspended, i'd resume it.
worker thread would look is input queue has something, and while it has, it will:
- extract the packet from the queue into local var
- do some potentially long processing
- make output "work results" packet. Assuming that is GUI updating that may be just a collection of key-value pairs, or some record of data fields with the set which data fields were filled and which are to be ignored.
- enqueue that packet into output queue (queue then post Work_Complete msg to main form)
- loop to 1.
if the input queue is empty, then the function exits, the thread does PostMessage Work_EmptyQueue and suspends itself until later would be awaken to do more work or freed.
When MainForm (in main thread again) receives Work_Complete it
- extracts all packets from the output queue into local vars
- merge them. (if i have p1=(label1='aaaa', label2='bbbb') and p2=(label3='cccc', label1='dddd') then the accumulated task would be setting (label1='dddd', label2='bbbb', label3='cccc');
- apply them (actually update GUI)
steps 2 and 3 are omitted if output queue is empty (it will be if merging happened on previous step). But not 4th.
steps 1 and 2 are separate. Since queue operations are thread-interlocking, the goal of step 1 is to extract data as fast as possible. Margine is to be done locally.
When MainForm receives Work_EmptyQueue it checks if input queue is not empty now and maybe resumes the worker thread. It optionally may do some GUI updating of status or whatever.
That is a rough sketch. It can be carved better to you certain cituation.