Yesterday1 I wrote about threads, noting that the only problem that I've found seems to be that if the window with the user interface (which calls the thread) is closed before the thread finishes its work, the thread appears to die. I searched the web for a description of this problem and how to solve it.
This tutorial holds the answer. Although it's written describing the case of a main program and a thread, it appears to be suitable for a 'son' form that is calling a thread. The first thing to do is to maintain a count of threads invoked by the form
Constructor TCorrel2Scales.Create; begin . . . threadcount:= 0; end;
Whenever a new thread is created ('DoCorrelThread (id1, id2, fdt ...'), the variable 'threadcount' is incremented. Two procedures have to be added: one is private ('HandleTerminate') and one is an event handler ('FormCloseQuery') - as follows
procedure TCorrel2Scales.HandleTerminate(Sender: TObject); begin Dec (threadcount); end; procedure TCorrel2Scales.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if threadcount = 0 then canclose:= true else canclose:= false; end;
No change was necessary in the thread unit. I tested this by first running a correlation of two scales from 2018 - many data points - before I added the above code (actually I had added it but neglected to connect the 'FormCloseQuery' handler to the 'OnFormCloseQuery' event) then closing the form (TCorrel2Scales) before the thread terminated. This caused the program to crash. After I connected the event to its handler, the same test worked - the form would not close until the thread had terminated.
So now I know.
Addition from a few hours later: it seems that I missed something in the tutorial. The thread has its OnTerminate event point to HandleTerminate, but in this example the thread is created within the calling form and so this works. In my case, the thread is created in a separate unit and so it would seem that there is no value that can be passed to the thread's OnTerminate event.
This is solved by defining a new type, TMyProc = Procedure (sender: TObject) of object. Then I can pass the HandleTerminate 'variable' to the thread code. In non-Delphi environments, this is known as a callback and occurs quite frequently in Windows code; even I've used it albeit very rarely.
While all of the above prevents closing the interface form while there is still a thread in existence, it doesn't solve - in fact, dodges - the original problem: how can I close the interface form while there is still a thread in existence. I suspect that the solution is to have the main form create the thread. I tried this but it appeared not to work: I still could not close the interface form. I shall have to work on this some more.
Internal links
[1] 1837
Title | Tags | ||
---|---|---|---|
140 | Where have I been all these months? | Literature, Peter Robinson, David Lodge | |
415 | Dieting has a number of destructive side effects | Martin Seligman, Diet, Acupuncture | |
516 | Friday is cooking day | Cooking | |
765 | Some days you're the pigeon and some days you're the statue | DBA, Films | |
1083 | The seven stage model for developing enhancements | DBA | |
1266 | Priority: LIKE cannot accept a variable | Priority tips | |
1430 | Potassium levels in food | Health, Food science, CPAP, Blood pressure | |
1536 | Gillian McPherson | 1971 |
No comments:
Post a Comment