Monday, October 14, 2024

Terminating threads

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



This day in history:

Blog #Date TitleTags
14014/10/2008Where have I been all these months?Literature, Peter Robinson, David Lodge
41514/10/2011Dieting has a number of destructive side effectsMartin Seligman, Diet, Acupuncture
51614/10/2012Friday is cooking dayCooking
76514/10/2014Some days you're the pigeon and some days you're the statueDBA, Films
108314/10/2017The seven stage model for developing enhancementsDBA
126614/10/2019Priority: LIKE cannot accept a variablePriority tips
143014/10/2021Potassium levels in foodHealth, Food science, CPAP, Blood pressure
153614/10/2022Gillian McPherson1971

No comments: