1
General / Re: Threads - stringlist and programming tips
« Last post by Warfley on Today at 12:37:31 pm »In your border case, where it is hard for you to ensure the granularity of the Terminated check inside your thread, you have several other options:First, this border case can *always* happen when you use a blocking call. I just found it because I am right now using gitlab zip Downloads. But you know what can also happen? Bad connectivity, where you may not receive any data for some time (remember the OS kills your application after only a few seconds of freezing. It does not need minutes).
- To return CanClose=False in the OnCloseQuery on your main form during the blocking periods. You can decide when depending on your Progress event handler.
- To continuously monitor thread.Finished after calling thread.Terminate and before thread.WaitFor:
thread.Terminate; while not thread.Finished do Application.ProcessMessages; thread.WaitFor; thread.Free;
- To call thread.Terminate and start async. polling of thread.Finished:
procedure Form1.AsyncWaitFor(Data: PtrInt); begin with TThread(Data) do if not Finished then Application.QueueAsyncCall(@AsyncWaitFor, Data) else begin WaitFor; Free; end; end; .... thread.Terminate; Application.QueueAsyncCall(@AsyncWaitFor, PtrInt(thread)); ....
In a previous post I wrote that the WaitFor can be postponed to a time when it will not block the GUI. And I'll always prefer (and recommend) to have valid references instead of such fire-and-forget contraptions.
To your approaches, you can't handle events whale doing waitfor, so how can you handle the OnClose?
Second your while not finished loop, yes that works, but then you don't need WaitFor, because your while not finished does exactly what WaitFor does. When your thread is finished using WaitFor afterwards is pointless. So yes, replacing WaitFor with a non blocking alternative is fine, and all I am advocating the whole time
And your third example is a much more complicated version of the OnTerminate event (which was the very first thing I recommened) with the bonus of again calling waitfor after the thread is finished, which is pointless. Do you really think that this is polling self queuing event is easier to use than the already existing OnTerminate event?
Lastly about FreeOnTerminate, it's actually not that hard to not use the thread again, just nil it's reference:
- // in main thread
- Thread.terminate;
- Thread := nil;
- //In your thread
- If terminated then
- begin
- FreeOnTerminate:= true;
- //your termination handler
- end;
If you only have one thread variable, setting it to nil not only removes any chance to accidentally call something on it, it is also a way to signalize that this thread has been killed
PS: I must admire your creativity, in this post you reinvented a non blocking waitfor, as well as a pilled version of OnTerminate to call before the blocking waitfor in order to avoid the problem of blocking waitfor (with the side effect that you made the blocking waitfor completely redundant)
So I'm wondering, why do you hang so much on waitfor, that you want to use it so hard that you even write code making it completely unnecessary, only to not have it blocking (because it literally does nothing in that situation)?