I have a procedure (let's call it proc1) that is called inside another one (mainproc) and from time to time the procedure proc1 hangs or executes for a time not worth waiting. mainproc is called inside the main thread. I would like to know what is the best decision in a case like this - is there a way to detect if the procedure won't respond after a certain amount of time without multithreading and if not what is the best way to handle the wait with threads :
procedure proc1;
begin
// statements that can be executed in a few milliseconds or much slower
end;
procedure mainproc;
begin
// statements part1
proc1;
// statements part2
end;
You need a guard thread monitoring entering and exiting of proc1.
For example, the proc1 sets an autoreset signalling event A on entering and sets an autoreset signalling event B on exiting; the guard thread is infinitely waiting on the event A; when A occurs the guard thread starts waiting for the event B for a given timeout; if timeout occurs then proc1 is hanging.
Related
I am reading Nick Hodges online and I have discovered the Queue but it is not behaving as I've expected and I couldn't understand what him and the documentation say. Look at this code:
TThread.CreateAnonymousThread(
procedure
begin
TThread.Queue(TThread.Current, procedure
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('start');
end);
Sleep(2000);
TThread.Synchronize(TThread.Current, procedure
begin
Memo1.Lines.Add('end');
end);
end
).Start;
I always use Synchronize but this time I have tried with Queue because according to Nick it is better in case of multiple requests since they won't be "serialized" and executed one by one. The code above works fine. Why this is not working instead?
TThread.CreateAnonymousThread(
procedure
begin
TThread.Queue(TThread.Current, procedure
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('start');
end);
Sleep(2000);
TThread.Queue(TThread.Current, procedure
begin
Memo1.Lines.Add('end');
end);
end
).Start;
In this case the Memo outputs the start but not the end. When I call:
Synchronize on the first and Synchronize on the second it works
Queue on the first and Synchronize on the second it works
Queue both times it's not working because I see only the start in the memo
The difference between queue and synchronize is that Synchronize() puts the call in a queue and waits for that call to be completed and Queue() puts the call in the queue and directly returns control to the thread.
However... and this is not mentioned in the official documentation, when a thread finishes, all the calls placed in the queue with Queue(AThread, AMethod), where AThread is its own thread, are removed.
You can see that clearly in the source of TThread.Destroy() where RemoveQueuedEvents(Self) is called.
RemoveQueuedEvents removes queued method calls. [...] If AThread is specified, then all method calls queued by this thread are removed.
So directly after your last Queue() your thread ends, TThread.Destroy() is executed and that last call(s) is/are removed from the queue.
There are some things you can do to solve this.
Like mentioned in the comments you can call TThread.Queue(nil, AMethod). B.T.W. Calling TThread.Queue(AMethod) is the same as TThread.Queue(Self, AMethod) so you'll always need to use the nil-variant if the thread is going to end and you want the call to finish.
But... If you still need the thread active when executing the call (for some data from it), you'll need to block the thread from exiting. You can do that by using Synchronize() as last queue-method. Note that the last synchronize doesn't have to be a real procedure. You can just call synchronize to a dummy-procedure at the end of the TThread.Execute like Synchronize(DummySync) (example). The queue is FIFO so the thread will wait until all calls in the queue are processed (including the empty dummysync).
Some extra information can be found on these pages
Ensure all TThread.Queue methods complete before thread self-destructs
http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/
hello friends i have a doubt regarding thread count. i have some code written below for thread
Procedure Mainthread.execute;
var
I : integer;
ScannerCh : array of ScannerChild; //array of ScannerChild
IpList : TStringlist;
IPs: Integer; //ipcount is count of iplist
Begin
IpList:=TStringList.Create;//creating stringlist
IPs := IpList.Count; //Ipcount is given value of iplists count
SetLength(ScannerCh, IPs); //Setting length of scannerch as ipcount
I:=0;
Repeat
While getthreadscount(getcurrentprocessid) >= tcount + 1(for main thread + Scannerch threads) do //Checking if is greater than tcount(thread input) by user
Sleep(30);
ScannerCh[I]:=ScannerChild.Create(True, IpList[i]);
ScannerCh[I].FreeOnTerminate:=True;
ScannerCh[I].LvHostname := LvHosts;
ScannerCh[I].Resume;
I:=I+1;
Sleep(20); //Sleep after each thread is created so that threads will enter critical section properly
until I = IPs;
end;
Scannerchild thread does some work. my code works perfectly if i have only these threads in process. If there are some other threads running to then i will be in trouble getting threadscount by getthreadscount function and i will not get to know which threads are getting terminated by getthreadcount function. so how can i enhance my code for many threads working. My logic is when scannerch thread terminates it should decrement count variable and when it gets created it should increment count variable. so that it will not be any problem if other threads are terminated or not. i just want to deal with scannerch thread termination and need to get counts of instances of running threads of scannerch. so that i put count variable instead of getthreadscount and my problem will be solved
Well, the question is easy enough to answer. Declare a count variable in the main thread class:
FScannerChildCount: Integer;
Whenever you create a new thread, increment this variable. Whenever a thread terminates, decrement it.
The incrementing is easy to do since you create the threads quite clearly and explicitly in the main thread code.
As for the decrementing, you need an OnTerminate event handler for each scanner child thread instance. This executes in the context of the process main thread, rather than your MainThread thread. FWIW, MainThread is a terrible name since everyone takes main thread to mean the main process thread. Because the OnTerminate event doesn't run in the same thread as your MainThread thread, you'll need synchronization.
When you increment the thread, use InterlockedIncrement. And when you decrement, use InterlockedDecrement.
The OnTerminate handler might look like this:
procedure MainThread.ScannerChildTerminate(Sender: TObject);
begin
InterlockedDecrement(FScannerChildCount);
end;
And you assign the event like any other event handler:
ScannerCh[I] := ...;
....
ScannerCh[I].OnTerminate := ScannerChildTerminate;
....
ScannerCh[I].Resume;
All of this said, whilst this may be the answer to the question you asked, you are attempting to solve your problem the wrong way. You should be using a thread pool to simplify the coding and avoid the overhead of creating and destroying short lived threads.
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?
I have a message queue based on a thread that processes messages being thrown at it. As some activities in the thread may be VCL commands they are performed in Synchronize. As soon Synchronize is called the thread hangs. Sample code:
TMessageQ = class (TThread)
...
procedure TMessageQ.do_msg;
begin
case CurrentMessage.Command of
cQSize: if Assigned (OnSize) then OnSize (CurrentMessage);
cQReady: if Assigned (OnReady) then OnReady (CurrentMessage);
end; // case
end; // do_msg /
procedure TMessageQ.doTask (Sender: TObject);
begin
while FQ.Count > 0 do
begin
FSection.Enter;
try
CurrentMessage := FQ.Dequeue;
finally
FSection.Leave;
end; // try..finally
Synchronize (do_msg);
end; // while
end; // doTask //
No statement in do_msg is ever being processed. Does somebody know what I am doing wrong?
TThread.Synchronize() blocks until the main thread processes the request. The main thread requires an active message loop in order to process requests (unless you manually call Application.ProcessMessages() or CheckSynchronize() periodically). If your thread's main work is always being invoked by TThread.Synchronize(), there is no point in using a thread at all. You could just use a timer or custom window message in the main thread instead and take out all of the unnecessary complexity.
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.