Let stay thread running on form close - multithreading

I made a syncing thread on my application and I want to know is there a way to let the thread stay open until it finishes it's syncing process, if i close the application form?

Call the thread's WaitFor method in your DPR file, after the Application.Run line. If the thread has already finished running, then WaitFor will return immediately. Otherwise, it will pause the main thread until the other thread terminates. (You'll have to make sure the variable still refers to a valid TThread instance, so don't set its FreeOnTerminate property.)
There are additional things you may wish to consider, beyond the simple issue of allowing the thread to continue running:
Programs only have limited time to stop running if the OS is shutting down or the user is logging out, so you might not have time to wait for synchronization to finish before the OS kills your program.
Users might wonder why the program is still running even though they told it to close, so consider showing some UI while synchronization continues.
Users might not care about synchronization if they're in a hurry and need the program to stop running immediately, so in that UI, you may wish to offer an "abort sync" command.

In the commentary to Rob's excellent answer, the question of showing UI whilst waiting was raised. If you need to show UI whilst waiting, then you will need a more advanced wait that TThread.WaitFor. This is what I use in its place, relying on MsgWaitForMultipleObjects.
procedure WaitUntilSignaled(Handle: THandle; ProcessMessages: Boolean);
begin
if ProcessMessages then begin
Application.ProcessMessages;//in case there are any messages are already waiting in the queue
while MsgWaitForMultipleObjects(1, Handle, False, INFINITE, QS_ALLEVENTS)=WAIT_OBJECT_0+1 do begin
Application.ProcessMessages;
end;
end else begin
WaitForSingleObject(Handle, INFINITE);
end;
end;
....
Form.Show;
WaitUntilSignaled(Thread.Handle, True);
Form.Close;

Related

Multithreading questions

1) This probably was asked a lot before, and I have read quite a lot about Sleep vs WaitForSingleObject, but still a little bit confused. As an example I have a simple background thread which is called from data-processing thread to show some message to the user without blocking data-processing thread. Which, in terms of performance (CPU usage / CPU time) is better in this case: http://pastebin.com/VuhfZUEg or http://pastebin.com/eciK92ze
I suspect that the shorter Sleep time is and the more flags I have, the worse performance is. On other hand with longer Sleep time performance will be better but reaction delay will increase, and with a lot of threads reaction delay will eventually become noticeable for user on low-end machine. Is that correct? So what is the best way to keep the "dormant", inactive threads?
2) Is SetEvent blocking (SendMessage) or non-blocking (PostMessage)?
3) In TForm.OnCreate event I have a following code:
procedure TFormSubsystem.FormCreate(Sender: TObject);
begin
Application.OnException:=LogApplicationException;
Application.OnActivate:=InitiateApplication;
end;
procedure TFormSubsystem.LogApplicationException(Sender: TObject; E: Exception);
var
ErrorFile: TextFile;
ErrorInfo: String;
begin
AssignFile(ErrorFile, AppPath+'Error.log');
if FileExists(AppPath+'Error.log') then
Append(ErrorFile)
else
Rewrite(ErrorFile);
ErrorInfo:=DateTimeToStr(Now)+' Unhandled exception';
if Assigned(Sender) then
ErrorInfo:=ErrorInfo+' in '+Sender.UnitName+'->'+Sender.ClassName;
ErrorInfo:=ErrorInfo+': '+E.Message;
try
WriteLn(ErrorFile, ErrorInfo);
finally
CloseFile(ErrorFile)
end;
end;
It's not the best way to log errors, but it's simple. The question is: What happens if there was an exception inside TSomeThreadAncestor.Execute or inside a method called via Synchronize?
4) What exactly is difference between Synchronize and Queue? Which one I should use when my background threads interact with GUI? I don't have race conditions and already use something like semaphores.
5) Is it safe to use such constructions?
procedure TShowBigDialoxBoxThread.Execute;
begin
while ThreadNotTerminated do begin
EventHandler.WaitFor(INFINITE);
if not(ThreadNotTerminated) then
Continue;
EventHandler.ResetEvent;
Synchronize(procedure begin
MessageDlgBig(FMsg, FDlgType, FButtons, FHelpContext, FDefaultButton, FDlgMinWidth);
end); // this kind of Synchronize call looks fishy
end;
end;
Or should I stick with calling a class method like in examples I provided above?
Edit:
I currently use Delphi XE5.
Polling in a thread core is a bad practice if you could wait with a blocking function. What you need to learn is that a context change is very expensive in terms of CPU usage. The only case you should poll, when there is no other oprtion (you can't be notified when to do the work).
The difference is the following:
Polling:
Your thread gives the control to the thread controller by calling 'Sleep()' which forces a context change. After the given period (and a bit), the thread controller will give the control back to your thread initiating another context change. Your thread checks if it has anything to do and if not, it calls 'Sleep()' which forces another context change. So your thread will surely not respond while the 'Sleep()' period is over and forces at least 2 other context changes per 'Sleep()' period.
Blocking:
Your thread gives the control to the thread controller by calling 'Sleep()' which forces a context change, but will not wake up until you signal it. It means only one context change per operation, and instant answer from the signalled thread.
Also: 'SetEvent()' is not blocking, but you should have asked it in a different question.

When does background threads prevent the process of being terminated?

Our program creates a background thread at the beginning of the program. The background thread does some database integrity checks and checks for stuff in the Internet using Indy. After 10 seconds, the background thread should be finished and since FreeOnTerminate is true, it will also clean itself up.
We have noticed that in some cases, if the user closes the program too quickly, the process will still be alive until the background thread is finished.
Since we couldn't exactly reproduce the issue, I have created a demo project to try a few things:
type
TBackgroundThread = class(TThread)
protected
procedure Execute; override;
end;
{ TForm1 }
var
bt: TBackgroundThread;
procedure TForm1.FormCreate(Sender: TObject);
var
i: integer;
begin
// Create a background thread which runs X seconds and then terminates itself.
bt := TBackgroundThread.Create(false);
bt.FreeOnTerminate := true;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
// The user closes the app while the background thread is still active
Sleep(2000);
Close;
end;
{ TBackgroundThread }
procedure TBackgroundThread.Execute;
var
i: integer;
x: cardinal;
begin
inherited;
// Simulate some work that the background thread does
x := MaxInt;
for i := 0 to MaxInt do
begin
x := Random(x);
end;
end;
The result is a bit surprising to me: After I close the MainForm, the process will be immediately terminated and the background thread will get hard-killed.
Now I have a few questions about this:
After the closing of the MainForm (= exit of the main thread), should I manually terminate all created threads via .Terminate or will that be done automatically?
Shall my threads only check for Self.Terminated or should they also check for Application.Terminated ?
Why does my busy thread as shown above gets immediately killed when I close the application? I expected that the process Project1.exe will run until all threads have finished by themselfes. (And as described above, we had seen an application where the main form is closed, but a thread is preventing the process of being closed).
How is it possible then, that our real application's process does not terminate because of a running background thread? Might it have something to do with the Internet stuff, which might cause the app to wait until a connection timeout is reached?
Closing the main form is not synonymous with exiting the main thread. Code continues to run after the form is closed. In particular, units are finalized.
If you handle your test thread's OnTerminate event, or put a breakpoint in the Terminate method, you'll see that it's not called automatically when your program exits. You'll have to call it yourself. But note also that a thread doesn't stop running just because Terminate is called. It continues running until it stops itself or it's terminated forcefully. Call WaitFor to wait for it to terminate.
Don't bother checking Application.Terminated; the thread's property should be sufficient.
Your thread gets terminated forcefully as your program exits because eventually your program calls ExitProcess, and one of the things the OS does there is to terminate all other threads. It doesn't call Terminate on them because the OS doesn't know about Delphi classes and methods.
You'll have to do some more debugging to determine why your program doesn't terminate promptly for your customers. You say you can't reproduce the problem in house, and you've written a test program that doesn't exhibit the problem, either. You'll have to find a customer who will cooperate with your further debugging efforts. Do you really know it's the thread that's holding things up, or is that just a guess so far?

Ensure all TThread.Queue methods complete before thread self-destructs

I have discovered that if a method queued with TThread.Queue calls a method that invokes TApplication.WndProc (e.g. ShowMessage) then subsequent queued methods are allowed to run before the original method has completed. Worse still, they don't seem to be invoked in FIFO order.
[Edit: Actually they do start in FIFO order. With ShowMessage it looks like the later one ran first because there is a call to CheckSynchronize before the dialog appears. This unqueues the next method and runs it, not returning until the latter method has completed. Only then does the dialog appear.]
I'm trying to ensure that all methods queued from the worker thread to run in the VCL thread run in strict FIFO order, and that they all complete before the worker thread is destroyed.
My other constraint is that I am trying to maintain strict separation of the GUI from the business logic. The thread in this case is part of the business logic layer so I can't use PostMessage from an OnTerminate handler to arrange for the thread to be destroyed (as recommended by a number of contributors elsewhere). So I'm setting FreeOnTerminate := True in a final queued method just before TThread.Execute exits. (Hence the need for them to execute in strict FIFO order.)
This is how my TThread.Execute method ends:
finally
// Queue a final method to execute in the main thread that will set an event
// allowing this thread to exit. This ensures that this thread can't exit
// until all of the queued procedures have run.
Queue(
procedure
begin
if Assigned(fOnComplete) then
begin
fOnComplete(Self);
// Handler sets fWorker.FreeOnTerminate := True and fWorker := nil
end;
SetEvent(fCanExit);
end);
WaitForSingleObject(fCanExit, INFINITE);
end;
but as I said this doesn't work because this queued method executes before some of the earlier queued methods.
Can anyone suggest a simple and clean way to make this work, or a simple and clean alternative?
[The only idea I've come up with so far that maintains separation of concerns and modularity is to give my TThread subclass a WndProc of its own. Then I can use PostMessage directly to this WndProc instead of the main form's. But I'm hoping for something a bit more light-weight.]
Thanks for the answers and comments so far. I now understand that my code above with a queued SetEvent and WaitForSingleObject is functionally equivalent to calling Synchronize at the end instead of Queue because Queue and Synchronize share the same queue. I tried Synchronize first and it failed for the same reason as the code above fails - the earlier queued methods invoke message handling so the final Synchronize method runs before the earlier queued methods have completed.
So I'm still stuck with the original problem, which now boils down to: Can I cleanly ensure that all of the queued methods have completed before the worker thread is freed, and can I cleanly free the worker thread without using PostMessage, which requires a window handle to post to (that my business layer doesn't have access to).
I've also updated the title better to reflect the original problem, although I'd be happy for an alternative solution that doesn't use TThread.Queue if appropriate. If someone can think up a better title then please edit it.
Another update: This answer by David Heffernan suggests using PostMessage with a special AllocateHWnd in the general case if TThread.Queue isn't available or suitable. Significantly, it's never safe to use PostMessage to the main form because the window can be spontaneously recreated changing its handle, which would cause all subsequent messages to the old handle to be lost. This makes a strong argument for me adopting this particular solution, since there's no additional overhead to creating a hidden window in my case since any application using PostMessage should do this - i.e. my separation of concerns argument is irrelevant.
TThread.Queue() is a FIFO queue. In fact, it shares the same queue that Thread.Sychronize() uses. But you are correct that message handling does cause queued methods to execute. This is because TApplication.Idle() calls CheckSynchronize() whenever the message queue goes idle after processing new messages. So if a queued/synched method invokes message processing, that can allow other queued/synched methods to being running even if the earlier method is still running.
If you want to ensure a queue method is called before the thread terminates, you should be using Synchronize() instead of Queue(), or use the OnTerminate event instead (which is triggered by Synchronize()). What you are doing in your finally block is effectively the same as what the OnTerminate event already does natively.
Setting FreeOnTerminate := True in a queued method is asking for a memory leak. FreeOnTerminate is evaluated immediately when Execute() exits, before DoTerminate() is called to trigger the OnTerminate event (which is an oversight in my opinion, as evaluating it that early prevents OnTerminate from deciding at termination time whether a thread should free itself or not after OnTerminate exits). So if the queued method runs after Execute() has exited, there is no guarantee that FreeOnTerminate will be set in time. Waiting for a queued method to finish before returning control to the thread is exactly what Synchronize() is meant for. Synchronize() is synchronous, it waits for the method to exit. Queue() is asynchronous, it does not wait at all.
I fixed this problem by adding a call to Synchronize() at the end of my Execute() method. This forces the thread to wait till all of the calls added with Queue() are completed on the main thread before the call added with Synchronize() can be called.
TMyThread = class (TThread)
private
procedure QueueMethod;
procedure DummySync;
protected
procedure Execute; override;
end;
procedure TMyThread.QueueMethod;
begin
// Do something on the main thread
UpdateSomething;
end;
procedure TMyThread.DummySync;
begin
// You don't need to do anything here. It's just used
// as a fence to stop the thread ending before all the
// Queued messages are processed.
end;
procedure TMyThread.Execute;
begin
while SomeCondition do
begin
// Some process
Queue(QueueMethod);
end;
Synchronize(DummySync);
end;
This is the solution I finally adopted.
I used a Delphi TCountdownEvent to track the number of outstanding queued methods from my thread, incrementing the count just before queuing a method, and decrementing it as the final act of the queued method.
Just before my override of TThread.Execute returns, it waits for the TCountdownEvent object to be signalled, i.e. when the count reaches zero. This is the crucial step that guarantees that all of the queued methods have completed before Execute returns.
Once all of the queued methods are complete, it calls Synchronize with an OnComplete handler - thanks to Remy for pointing out that this is equivalent to but simpler than my original code that used Queue and WaitForSingleObject. (OnComplete is like OnTerminate, but called before Execute returns so that the handler can modify FreeOnTerminate.)
The only wrinkle is that TCountdownEvent.AddCount works only if the count is already greater than zero. So I wrote a class helper to implement ForceAddCount:
procedure TCountdownEventHelper.ForceAddCount(aCount: Integer);
begin
if not TryAddCount(aCount) then
begin
Reset(aCount);
end;
end;
Normally this would be risky, but in my case we know that by the time the thread starts waiting for number of queued methods outstanding to reach zero no more methods can be queued (so from this point once the count hits zero it will stay at zero).
This doesn't completely solve the problem of queued methods that handle messages, in that individual queued methods could still appear to run out of order. But I do now have the guarantee that all queued methods run asynchronously but will have completed before the thread exits. This was the primary goal, because it allows the thread to clean itself up without the risk of losing queued methods.
A few thoughts:
FreeOnTerminate is not the end of the world if you want your thread to delete itself.
Semaphores let you maintain a count should you feel the need, there are such constructs.
There's nothing to stop you writing or using your own queueing primitives and AllocateHWnd if you want some fine grained control.

ISAPI Extension TerminateExtension thread deadlock

I needed to create statefull ISAPI extension for my project. I successfully made a TSession object that is contained in a TSessionList = class(TObject). For cleanup of expired sessions I made a cleanup thread (TThread descendant) that periodically scans TSessionList and frees all expired sessions.
I create the TSessionList and the CleanupThread in the dpr main execution block. Which is just fine. But actually I am not sure, where to put the destruction of CleanupThread. From documentation I found that ISAPI extension has to export TerminateExtension, which gets called just before the extension is unloaded. Default Delphi ISAPI extension of course exports such a function. So I've "overriden it" = exported my TerminateExtension that frees my session objects and then call default ISAPIAPP.TerminateExtensionProc.
Here it is how it looks like:
function TerminateExtension(dwFlags: DWORD): BOOL; stdcall;
begin
DoneSessions;
Result:= ISAPIApp.TerminateExtension(dwFlags);
end;
exports
GetExtensionVersion,
HttpExtensionProc,
TerminateExtension;
begin
CoInitFlags := COINIT_MULTITHREADED;
Application.Initialize;
InitSessions;
Application.CreateForm(TSOAPWebModule, SOAPWebModule);
Application.Run;
end.
The CleanupThread destruction is done in DoneSessions this way:
begin
CleanupThread.Free;
SessionList.Free;
end;
The CleanupThread is simple descendant of TThread, so do not look for anything specific in its destruction code.
The problem is that the TerminateExtension freezes just in CleanupThread.Free. Debugging further I did find that freeze happens in the TThread.WaitFor. I suspect there must be some kind of thread deadlock = ISAPI worker thread is waiting for my extension to terminate, which waits in TThread.WaitFor for the main thread to get signaled (or whatever).
I know I could overcome this situation calling CleanupThread.Terminate, then using direct WaitForSingleObject (or Multiple???) and finally freeing it. But that sounds a bit ... nonstandard.
Therefore my question is: How and when should i Free (Terminate - WaitFor - Destroy) any support threads in ISAPI extension to avoid thread deadlock?
BTW: I already found the same in standard DLL. If you put any thread.WaitFor in the dll unload proc, your main app freezes just in library unload. So the same question/answer hopefully applies here.
You should try signalling the thread terminate before calling free, for example;
CleanupThread.Terminate;
if CleanupThread.Waitfor(60000)<>WR_Abandoned then //wait for 60sec for cleanup
CleanupThread.free
else
//do something sensible on timeout or error
But without knowing what, exactly, the cleanup thread is trying to do it is hard to say what could be causing a deadlock. Often these are the result of race conditions, especially if a terminate & waitfor times out, so you need to specify what the thread is doing.
As a hack (and not good practice for multithreading) you can force a thread to exit using the winapi call TERMINATETHREAD (in the Windows unit);
TerminateThread(CleanupThread.handle,0);
As this forces an immediate exit on the thread but also means no thread cleanup is performed - remember that calling TTHREAD.TERMINATE does not guarantee that a thread will exit - this is entirely dependant on your thread code, if something is blocking your thread then it will not terminate in the normal manner. TerminateThread can solve this, at the expense of the code simply stopping where it is with no regard for any resource freeing or what other threads are up to.

Some help with TThread (Terminate, FreeOnTerminate and other adventures in the realm of threading)

I'm trying the achieve the following (using Delphi7):
After logging in to my program, the user gains control, but in the background a separate thread downloads a file from the Internet to check if the current license key is blacklisted. If it is, the user receives a prompt and the program terminates.
So I've created a separate TThread class which downloads the blacklist from the Net using InternetOpenURL/InternetReadFile.
My problem is the following:
If the user quits my program before the downloading in the background finishes, the license manager thread should be terminated by the main thread.
If the thread has done its job, it should terminate automatically.
If I use FreeOnTerminate := true I can't terminate the thread from the Main thread. But otherwise, how can I make the thread free its resources after it has done its job?
My other question is:
If the license key is blacklisted, I use Synchronize to do something with certain resources of the Application's main form.
But how do I know if the user has already closed the app and the program is in FormDestroy of the main form, for example? If I Synchronize in the wrong time, it could lead to access violations...
Thanks!
First, in your check thread object, create a "completed" flag. You can check this is true to determine if all is well. As Chris T suggests, have the thread set a global to indicate things are good/bad, so that the main thread can use something like a timer to check that and that all is well or take appropriate action.
Then, if your app wants to quit early, call
MyThread.Terminate;
MyThread.WaitFor;
And in the thread, check for Terminated being set at appropriate points. This way you can close down nicely.
For the second question, don't bother updating the UI from the thread. Just set a global flag. i.e. IsBlackListed := true;
Now you can use that global flag as the basis for nagging the user, in response to some user-initiated action. Such as OnFileSave...
ShowMessage('I would love to save that file for you, but unfortunately, you are using a blacklisted key.');
IsBlackListed Redux....
// globally...
var
IsBlackListed : integer;
...
initialization
IsBlackListed := 0;
...
// in your thread:
if OhMyGodThisIsABlackListedKey then
IsBlackListed := 1;
... Back in the main code, maybe in the OnSaveMyData event:
if IsBlackListed then
begin
IsBlackListed := -1; // so we don't repeat ourselves
MessageBox('Hey, you naughty pirate!');
MyDBConnection.Whatever.DoSQL('insert into licensetable (name,key) values(pirate,blacklisted);
end;
I think this is what you're trying to do.... Assign an OnTerminate() event to the TThread, which gets excuted as part of your main thread when the worker thread is terminated. You can do all of your UI updates there (the black listing). Make a property of your worker thread such as 'DownloadComplete', and only do the blacklisting/validating if thats set to true in the OnTerminated event. That should allow the thread to free itself regardless of the state of the download when the program runs, as long as you .watifor() it before the program exits.

Resources