Steven pointed out that Ray's code did not gracefully handle the application closing. If the application closed while there were still transactions processing, the application would simply appear to hang, with its user interface frozen, until either all the transactions were processed, or the user killed the process.
The solution is to check Application.Terminated in the thread loop:
while TransactionsPending and not Application.Terminated do //etc... end;
With this check in, when the application is closed, the thread will finish processing the transaction it's processing, and then gracefully exit.
4 Comments
This solution is in itself a bug, IMHO.
Now the thread is dependent on the Forms unit. (for access to the Application object). Generally speaking, worker threads shouldn’t require the presence of a GUI. Yes, you need to notify the thread that the app is closing and it should gracefully exit, but not by making it dependent on the GUI.
No, if the main thread terminates, all other threads will get killed automatically. The application will not hang.
A program terminates like this: The message loop in Application.Run terminates and Application.Run returns to the caller, the DPR file. Execution calls off the end of the DPR file and proceeds to unit finalization. After all the units have been finalized, the RTL calls ExitProcess. No running thread can survive that call. The entire process goes away.
It’s still possible for the program to hang, but it’s unlikely. ExitProcess’s documentation has details.
For all we know, part of the application’s original shutdown code includes emptying the transaction queue of pending transactions. That will make TransactionsPending be False, so the thread would terminate gracefully anyway. But only if it happened to finish processing its current transaction before the main thread terminated. Otherwise, the thread would terminate during the call to Settle.
Rob:
Experimenting tells otherwise. If you have a thread running an infinite loop, and close the application (specifically, you close the main form), the application attempts to terminate, but your worker thread does not terminate, and the application hangs.
Sorry Jacob - I don’t get your result (testing with a simple while True do example). In line with Craig’s comments, I thought that it would perhaps be best to check TThread.Terminated instead, but that doesn’t actually work.
See, DoTerminate is only called once Execute exits, so unless you terminate the thread manually on application shutdown the thread will simply exit (as Rob said) and not call OnTerminate.
So what if my thread absolutely needs to do some cleanup when it closes? Then I *do* need to check Application.Terminated and exit my Execute method. Sorry, no apparent way around it. OK, perhaps you could peek in the message queue for WM_QUIT? Haven’t checked.
Btw, TApplication does reside in Forms.pas and does indeed have some specific UI features, but calling Application.Terminated doesn’t actually end up binding the thread to the UI. The separation should have been better, but I can live with this until another solution presents itself.
Post a Comment