Delphi TIdTcpServer force stop IdSync after someTimeOut - multithreading

I need to develop a TCP server and client with persistent connections using Indy and Delphi XE2. Almost everything is going well.
This service is a critical service, so I need to put in some protection in the server to prevent unnecessary processing or freezes. Because of this, I create a thread to check a timeout for critical processes.
I made this TIdSync class:
type
TSync = class(TIdSync)
protected
procedure DoSynchronize; override;
end;
procedure TSync.DoSynchronize;
var
oTimeOut: TThreadTimeOut;
begin
...
oTimeOut := TThreadTimeOut.Create(AContext, WaitTimeOut*2, Self);
oTimeOut.Start;
...
// the code below is just a test, **this is the key to my question**
// if something goes wrong in any subroutine of DoSynchronize, I want
// to stop execution of this object and destroy it. In the thread above
// I want to test when the timeout elapses. If this IdSync object still
// exists and if this routine is still executing, I want to stop execution
// of any routine or subroutine of this object to avoid freezing the
// service and stop memory consumption and CPU usage
while true do begin
Sleep(100);
end;
//If everything is OK
oTimeOut.Stop;
end;
procedure TThreadTimeOut.execute;
var
IniTime: DWORD;
begin
IniTime := GetTickCount;
while GetTickCount < IniTime + TimeOut do begin
Sleep(SleepInterval);
if StopTimeOut then
Exit;
end;
if ((Terminated = False) or (StopTimeOut)) and (IoHandler <> nil) then begin
IOHandler.Connection.IOHandler.Close;
IdSync.Free; //here I try to make things stop execution but the loop to test is still running
end;
end;
This code above works fine to stop receiving and sending data when the timeout elapses, but not to stop execution of TIdSync. How can I do that?

There is no timeout logic in TIdSync (largely because there is no timeout logic in TThread.Synchronize(), which TIdSync uses internally).
You cannot destroy a TIdSync object while it is running. A synced procedure cannot be aborted prematurely once it has been queued for execution, or has started running. It must be allowed to run to completion.
TIdSync.DoSynchronize() (or any method synced with TThread.Queue() or TThread.Synchronize()) is executed in the context of the main UI thread. Long-running code should be executed in its own thread, not in the main UI thread. Make sure the main UI thread is not blocked from processing new messages and sync requests in a timely manner.
If you want to stop a synced procedure, you need to have it handle a TEvent object or other flag which worker threads can signal when needed, and that the procedure checks periodically so it can exit as soon as possible (either gracefully or by raising an exception).
Synched operations of any nature should be short, to prevent blockages/deadlocks, resource starvation, etc. You need to re-think your design. You are doing things the wrong way.

Related

Delphi Thread Handling Best Practice to Pause and Resume

My application continuously syncs data with another database and I am running this process in a thread of which I have very little knowledge.
I am pulling in data from an Actian Zen database. Formerly Pervasive.SQL and updating my database in NexusDB.
It is a continuous operation of refreshing data in NexusDB.
The thread is called from the main form.
The work is done here:
procedure tImportThread.Execute();
begin
while (not Terminated) do
Begin
TThread.Sleep(3000);
CheckPause;
//My work
end;
end;
At certain points in my application I want to pause and resume the thread.
I have read this post "Pausing" A Thread With A Property and the wiki it refers to.
I have implemented the solution offered in the above post for lack of other examples and lack of knowledge on my part. For the most part the thread is working fine except that I would like to pause and unpause the running at certain times and would like to see a log that it was actually paused or resumed.
What I want to know is:
Do I just use PAUSE and UNPAUSE in the parts of my application to suspend the thread and restart it?
I want to test with a button to Pause and Resume the thread but not sure how to implement:
If thread running then Pause else Unpause
Part of the solution offered includes this code:
procedure TMyThread.CheckPause;
var
SignaledEvent: THandleObject;
begin
while not Terminated do
begin
case TEvent.WaitForMultiple(FWaitEvents, INFINITE, False, SignaledEvent) of
wrSignaled: begin
if SignaledEvent = FRunEvent then Exit;
Break;
end;
wrIOCompletion: begin
// retry
end;
wrError: begin
RaiseLastOSError;
end;
end;
SysUtils.Abort;
end
Where to create an entry into a log file to show that the thread is now paused. I have a simple writelog function to create an entry but where in the above should I put it? The same when the thread is resumed.
Does it matter whether the thread is paused or running when the application terminate? Do I just use this code?
if Assigned(TMyThread) then
begin
TMyThread.Free;
end;

Omnithread unobserved nested thread not released when expected

Background
My Flagship App seems to leak memory. Well, not really but just during runtime. Investigating this showed the memory 'leak' is resolved when the app closes, but not in between.
I am using a background thread , that iself starts another thread. Both threads (parent and child) are 'Unobserved' which should result in the TOmniTaskControl object to be released and freed when the tread is finished.
Experimenting code
procedure TfrmMain.MyTestProc(const aTask: IOmniTask);
begin
sleep(100);
SGOutputDebugStringFmt('%s.MyTestProc for %s',[ClassName,aTask.Name]);
sleep(100);
end;
procedure TfrmMain.MyNestedTestProc(const aTask: IOmniTask);
var lTask:IOmniTaskControl;
begin
sleep(100);
SGOutputDebugStringFmt('%s.MyTestProc for %s',[ClassName,aTask.Name]);
lTask:=CreateTask(MyTestProc,'NestedTask');
lTask.Unobserved.Run;
sleep(100);
end;
procedure TfrmMain.btSimpleThreadClick(Sender: TObject);
var lTask:IOmniTaskControl;
begin
lTask:=CreateTask(MyTestProc,'SimpleThread');
lTask.Unobserved.Run;
end;
procedure TfrmMain.btNestedThreadClick(Sender: TObject);
var lTask:IOmniTaskControl;
begin
lTask:=CreateTask(MyNestedTestProc,'NestedThread');
lTask.Unobserved.Run;
end;
When debugging, and setting breakpoint on TOmniTaskControl.Destroy, and having a watch TOmniTaskControl.Name on I see the following:
btSimpleThreadCLick:
TOmniTaskControl for 'SimpleThread' gets to be created
TOmniTaskControl for 'SimpleThread' gets to be destroyed
btNestedThreadCLick:
TOmniTaskControl for 'NestedThread' is Created
TOmniTaskControl for 'NestedTask' is Created
TOmniTaskControl for 'NestedThread' is Destroyed
Problem: TOmniTaskControl for 'NestedTask' is NOT destroyed. Another issue is that the OnTerminate isn't called either.
Then, when closing the app, the TOmniTaskCOntrol for 'SimpleThread' is destroyed. (And also, the OnTherminate is fired)
Workaround
I came up with this solution which seems to do the trick. The thing is however, I do usually NOT run my subthreads from a form where a TOmniEventMonitor is at hand. So I'd have to create a global TOmniEventMonitor object for this.
But isn't this the whole point of the UnObserved method?
procedure TfrmMain.MyNestedTestProc(const aTask: IOmniTask);
var lTask:IOmniTaskControl;
begin
sleep(100);
SGOutputDebugStringFmt('%s.MyTestProc for %s',[ClassName,aTask.Name]);
lTask:=CreateTask(MyTestProc,'NestedTask');
lTask.MonitorWith(OmniEventMonitor).Run; // OmniEventMonitor is a component on my form
sleep(100);
end;
Well, secondary workarounbd... kind-of. It does not allow for my thread to be freed unattended.
if I change the NestedTestProc to the code below, then the NestedTaskgets to be destroyed at the expected moment. Unfortunately, this solution is clearly not 'Unobserved'
procedure TfrmMain.MyNestedTestProc(const aTask: IOmniTask);
var lTask:IOmniTaskControl;
begin
sleep(100);
SGOutputDebugStringFmt('%s.MyTestProc for %s',[ClassName,aTask.Name]);
lTask:=CreateTask(MyTestProc,'NestedTask');
try
lTask.Run;
lTask.WaitFor(2000);
finally
lTask:=nil;
end;
sleep(100);
end;
Update 20201029 >>
An invalid handle (1400) error typically occurs when the master task was completed and its associated Monitor was already destroyed.
So - The 'Master' task thread should not die in case there is an "owned" monitor that is monitoring other threads.
So to check this, I changed the timing (using sleep()) to ensure the child task was completed before the master task is completed.
The Invalid handle error is gone now, and the COmniTaskMsg_Terminated message gets to be posted successfully.
But still the ComniTaskMsg_Terminated from the child task is not processed. (I expected the thread of the MasterTask to handle this.)
IMO there are 2 problems:
life time management of the Unobserved monitor
shutdown management of the Unobserved monitor, which should keep the "owning" thread alive and keep processing messages until all
monitored threads/tasks are gone.
Also I wonder whether these shutdownmessages hould be handled/processed by the Application main thread (It seems this is the case now) or otherwise through a separate thread that checks all the monitors in GTaskControlEventMonitorPool . AIA, pretty complicated stuff :s...
Giving this some thought, monitors that were created by the application main thread (thus Monitor.ThreadID=MainThreadID) should be handle their messages in the main thread message loop, and all others probably need to be handled by a separate thread... Its just too confusing! I will see if I write a unit test for this, just to demonstrate what I expect to happen.
<< Update 20201029
The question
With OmniThreadLibrary, How can I use unobserved threads inside threads, and avoid the described memory leak?

How to check if Anonymous thread is running

i want to check if Anonymous thread is running,i have an idea which is to monitor the thread status every 1s, if it Exists, restart the work again..
I've got the thread ID, now how to check the status ?
procedure TForm2.Button5Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(procedure ()
var i : integer;
begin
inc(i);
label1.caption := TThread.Current.ThreadID.ToString;
end).Start;
end;
Threads do not just stop. If your thread stops functioning it is because your code has a defect. Even the simple code in the question contains two defects. It reads a local variable before it is initialized and it uses a VCL method away from the main thread.
The entire premise of your question is wrong. You don't need to monitor whether or not your thread is still running. You simply need to fix the defects in your code so that it does not fail.
A better understanding of what threads are and how to use them, will help you. A thread is usually a way to get something done without holding up the user-interface. If you want the user to wait for something to finish, don't use a thread, just put the work code in the buttonclick event handler without any thread creating.
You said
every 1s, if it Exists, restart the work again
That makes no sense. If the thread exists, it's still busy working so there's no need to restart it. Maybe you should tell us what work you want the thread to do exactly.
In the example below (taken from Background Operations on Delphi Android, with Threads and Timers, you can see that the Synchronize procedure is called when the work is done, so that's how you know that that thread is done with it's work.
procedure TForm2.Button5Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(procedure ()
var i : integer;
begin
inc(i); // some work here
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
label1.Caption := TThread.Current.ThreadID.ToString;
end);
end).Start;
end;
TThread.CreateAnonymousThread is a function which returns an instance of new Thread like this:
var ms:TThread;
ms:=TThread.CreateAnonymousThread( .....
You have an instance - ms "aka Thread" and you can work with this object...

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?

Self Suspending a thread in Delphi when it's not needed and safely resuming

This question involves Delphi and XE specifically deprecating Suspend and Resume. I have read other posts and I have not found a similar usage so far, so I’m going to go ahead and ask for a discussion.
What I’d like to know is there a better way to pause a thread when it is not needed?
We have a Delphi class that we have used for years that is basically a FIFO Queue that is associated with a threaded process. The queue accepts a data object on the main thread and if the thread is suspended it will resume it.
As part of the thread’s Execute process the object is popped out of the queue and processed on the thread. Usually this is to do a database lookup.
At the end of the process a property of the object is updated and marked as available to the main thread or passed on to another queue. The last (well it really is the first) step of the Execute process is to check if there are any more items in the queue. If there is it continues, otherwise it suspends itself.
They key is the only suspend action is inside the Execute loop when it is completed, and the only resume during normal operations is called when a new item is placed in the queue. The exception is when the queue class is being terminated.
The resume function looks something like this.
process TthrdQueue.MyResume();
begin
if Suspended then begin
Sleep(1); //Allow thread to suspend if it is in the process of suspending
Resume();
end;
end;
The execute looks similar to this
process TthrdQueue.Execute();
var
Obj : TMyObject;
begin
inherited;
FreeOnTerminate := true;
while not terminated do begin
if not Queue.Empty then begin
Obj := Pop();
MyProcess(Obj); //Do work
Obj.Ready := true;
end
else
Suspend(); // No more Work
end; //Queue clean up in Destructor
end;
The TthrdQueue Push routine calls MyResume after adding another object in the stack. MyResume only calls Resume if the thread is suspended.
When shutting down we set terminate to true and call MyResume if it is suspended.
I'd recommend the following implementation of TthrdQueue:
type
TthrdQueue = class(TThread)
private
FEvent: THandle;
protected
procedure Execute; override;
public
procedure MyResume;
end;
implementation
procedure TthrdQueue.MyResume;
begin
SetEvent(FEvent);
end;
procedure TthrdQueue.Execute;
begin
FEvent:= CreateEvent(nil,
False, // auto reset
False, // initial state = not signaled
nil);
FreeOnTerminate := true;
try
while not Terminated do begin
if not Queue.Empty then begin
Obj := Pop();
MyProcess(Obj); //Do work
Obj.Ready := true;
end
else
WaitForSingleObject(FEvent, INFINITE); // No more Work
end;
finally
CloseHandle(FEvent);
end;
end;
Instead of suspending the thread, make it sleep. Make it block on some waitable handle, and when the handle becomes signalled, the thread will wake up.
You have many options for waitable objects, including events, mutex objects, semaphores, message queues, pipes.
Suppose you choose to use an event. Make it an auto-reset event. When the queue is empty, call the event's WaitFor method. When something else populates the queue or wants to quit, have it call the event's SetEvent method.
I preferred technique is to use the OS message queue. I'd replace your queue object with messages. Then, write a standard GetMessage loop. When the queue is empty, it will automatically block to wait for a new message. Turn a termination request into just another message. (The TThread.Terminate method simply isn't a very useful function once you start doing anything interesting with threads because it's not virtual.)
There is a library to allow implementation of producer-consumer queue in Delphi using condition variables. This scenario is actually the example discussed.
The classic example of condition
variables is the producer/consumer
problem. One or more threads called
producers produce items and add them
to a queue. Consumers (other threads)
consume items by removing the produced
items from the queue.

Resources