Why does this code block my main thread? - multithreading

I need my Thread work independent of Form.
For example I have a endless loop in my Thread:
procedure TCustomThread.doProc;
begin
repeat
.
.
.
until (1 = 2);
end;
procedure TCustomThread.Execute;
begin
inherited;
Synchronize(doProc);
end;
.
.
.
procedure TForm1.Button1Click(Sender: TObject);
var
thrd : TCustomThread;
begin
thrd := TCustomThread.Create(True);
thrd.Resume;
Application.ProcessMessages;
end;
Now, when I click on Button1, my Thread runs but main Form is locked. How can I avoid suspending Form?

The call to ProcessMessages is wrong and should be removed. As a broad and general rule, calls to ProcessMessages should be avoided. And this one serves no purpose at all.
The rest of your code simply runs a non-terminating loop. It does so using Synchronize which ensures that the non-terminating loop runs on the main thread. Hence the main thread is unable to service its message loop.
The entire purpose of threads is to be able to execute separate threads of execution. By using Synchronize you are running all your code in the main thread. Your code is equivalent to placing the non-terminating loop in the main thread.
You want to execute code in a different thread. So you should avoid the call to Synchronize. That should only be used for small, quick pieces of work that must execute on the main thread. Typically GUI updates.
Your execute method should be:
procedure TCustomThread.Execute;
begin
while not Terminated do
begin
....
end;
end;
This introduces your loop, but the loop now executes in the thread. You can now add the useful code of your thread inside the body of the loop.
Remember that any use of VCL components must happen on the main thread. And that's where Synchronize is to be used.

TThread.Synchronize() runs the specified procedure in the context of the main thread, not in the context of the worker thread. So your loop is running in the main thread and is not letting hte main thread process new messages from its message queue. That is why your UI is not responding while your thread is running.
You need to restructure your thread to something more like this:
procedure TCustomThread.doUpdateUI;
begin
... do something that updates the UI here ...
end;
procedure TCustomThread.Execute;
begin
while not Terminated do
begin
... do something in the worker thread ...
Synchronize(doUpdateUI);
... do something else in the worker thread ...
end;
end;
var
thrd : TCustomThread = nil;
procedure TForm1.Button1Click(Sender: TObject);
begin
if thrd = nil then
thrd := TCustomThread.Create(False);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if thrd <> nil then
begin
thrd.Terminate;
thrd.WaitFor;
FreeAndNil(thrd);
end;
end;

Related

I would like to do two things at the same time in delphi, for example, run two timer events simultaneously

I would like to do two things at the same time in delphi, for example, to run at the same time as the two-timer,,,,How to use a method that?
For example, let's look at this simple example, here are two timers and these timers running consecutively but I would like to run the timers at the same time,,,but how?
procedure TForm1.Button1Click(Sender: TObject);
begin
if Button1.Caption = 'START' then
begin
Timer1.Enabled := True;
Timer2.Enabled := True;
Button1.Caption := 'FINISH'
end
else if Button1.Caption = 'FINISH' then
begin
Timer1.Enabled := False;
Timer2.Enabled := False;
Button1.Caption := 'START';
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i : integer;
begin
for i := 0 to 50 do
begin
Memo1.Lines.Add(IntToStr(i));
sleep(500);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
k : integer;
begin
for k := 0 to 50 do
begin
Memo2.Lines.Add(IntToStr(k));
sleep(500);
end;
end;
end.
" I would like to run the timers at the same time,,,but how?"
This is not possible.
Everything in the main thread is running in one sequence.
There is no way to run two procedures at the same time, even using timers.
The idle part of the main thread checks the message queue for messages.
They are handled one by one. This is what is happening when your timer events are called.
During the execution of your timer event, the main thread does nothing but execute this event.
So be careful with the complexity of your timer event code and keep it short and simple.
If you want better multitasking performance (or your timer event is too complex), you must use threads.
Threads are executed "parallel" to your main thread with their own stack.
How parallel is interpreted depends on the OS and also how many cores the CPU has.
Access to the VCL part from your threads is not possible without proper protection, like Synchronize.
This means that the thread waits until the synchronized part has been executed in the main thread.
It is also possible to queue messages asynchronously from the thread to be executed main thread.
You can find an example of multithreading in the Delphi samples, ThrdDemo.
Do not call Sleep inside the TTimer.OnTimer handler. Instead, set yout timer interval to 500 and it will fire every 500 miliseconds. Both timers will fire and you will have a sensation that two things are running at the same time.
It´s an ilusion, however, since both codes are running inside the same thread (the main thread), but depending on your requirements, the behavior may be acceptable.

Synchronize appears to hang thread

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.

How to implement thread which periodically checks something using minimal resources?

I would like to have a thread running in background which will check connection to some server with given time interval. For example for every 5 seconds.
I don't know if there is a good "desing pattern" for this? If I remember corretly, I've read somewehere that sleeping thread in its execute method is not good. But I might be wrong.
Also, I could use normal TThread class or OTL threading library.
Any ideas?
Thanks.
In OmniThreadLibrary, you would do:
uses
OtlTask,
OtlTaskControl;
type
TTimedTask = class(TOmniWorker)
public
procedure Timer1;
end;
var
FTask: IOmniTaskControl;
procedure StartTaskClick;
begin
FTask := CreateTask(TTimedTask.Create())
.SetTimer(1, 5*1000, #TTimedTask.Timer1)
.Run;
end;
procedure StopTaskClick;
begin
FTask.Terminate;
FTask := nil;
end;
procedure TTimedTask.Timer1;
begin
// this is triggered every 5 seconds
end;
As for sleeping in Execute - it depends on how you do it. If you use Sleep, then this might not be very wise (for example because it would prevent the thread to stop during the sleep). Sleeping with WaitForSingleObject is fine.
An example of TThread and WaitForSingleObject:
type
TTimedThread = class(TThread)
public
procedure Execute; override;
end;
var
FStopThread: THandle;
FThread: TTimedThread;
procedure StartTaskClick(Sender: TObject);
begin
FStopThread := CreateEvent(nil, false, false, nil);
FThread := TTimedThread.Create;
end;
procedure StopTaskClick(Sender: TObject);
begin
SetEvent(FStopThread);
FThread.Terminate;
FThread.Free;
CloseHandle(FStopThread);
end;
{ TTimedThread }
procedure TTimedThread.Execute;
begin
while WaitForSingleObject(Form71.FStopThread, 5*1000) = WAIT_TIMEOUT do begin
// this is triggered every 5 seconds
end;
end;
OTL timer implementation is similar to the TThread code above. OTL timers are kept in priority list (basically the timers are sorted on the "next occurence" time) and internal MsgWaitForMultipleObjects dispatcher in TOmniWorker specifies the appropriate timeout value for the highest-priority timer.
You could use an event and implement the Execute method of the TThread descendant by a loop with WaitForSingleObject waiting for the event, specifying the timeout. That way you can wake the thread up immediately when needed, e.g. when terminating.
If the thread runs for the life of the app, can be simply terminated by the OS on app close and does not need accurate timing, why bother with solutions that require more typing than sleep(5000)?
To add another means of achieving a 5-sec event it is possible to use the Multimedia Timer which is similar to TTimer but has no dependence on your application. After configuring it (you can setup one-shot or repetitive) it calls you back in another thread. By its nature it is very accurate (to within better than 1ms). See some sample Delphi code here.
The code to call the timer is simple and it is supported on all Windows platforms.
Use CreateWaitableTimer and SetWaitableTimer

TThread.Execute is not called as expected

I am trying to display an activity indicating overlay (a spinning circle of dots) during a lengthy operation in my application. For this, i created a borderless transparent form with a TImage and an Imagelist, which i sought to update in a thread during the time the main thread is busy.
The problem i encountered is that the lengthy operation does not seem to get 'interupted' by my thread. The thread.Execute function loops a few times before the lengthy operation starts, and then again when the operation is finished.
It seems as if the thread is starved for some reason. I tried to raise it's priority, but could not see any effect.
Does anyone have similar experiences to share, or maybe even a solution?
Source code of thread function
procedure TIndicatorThread.Execute;
begin
inherited;
while(not Terminated) do
begin
fDlg.fCurindex := (fDlg.fCurindex+1) mod 12;
Synchronize(UpdateImage);
Application.ProcessMessages;
sleep(80);
end;
Synchronize(fDlg.close);
Synchronize(fDlg.Free);
end;
main thread
begin
[...]
myThread := TIndicatorThread.Create;
mythread.Resume;
Init_SomeUIRelatedstuff;
Application.ProcessMessages;
DoLengthyOperation;
mythread.Terminate;
Your are doing the bulk of your thread work inside of Synchronize(), which delegates the work back to the main thread. If the main thread's lengthy operation is not processing new messages from the message queue, then Synchronize() has to wait. That is why your thread does not do anything while the lengthy operation is running.
Your code is a poor example of how to use a thread effectively. What you should have done instead is perform the lengthy operation itself in the thread, and let the main thread handle the UI updates while the thread is running, eg:
procedure TWorkThread.Execute;
begin
DoLengthyOperation;
end;
begin
...
Init_SomeUIRelatedstuff;
Application.ProcessMessages;
myThread := TWorkThread.Create(False);
while WaitForSingleObject(myThread.Handle, 80) = WAIT_TIMEOUT do
begin
fDlg.fCurindex := (fDlg.fCurindex+1) mod 12;
UpdateImage;
Application.ProcessMessages;
end;
mythread.Free;
fDlg.Close;
fDlg.Free;
...
end;
I used GIF image component that can show animated GIFs (http://www.tolderlund.eu/delphi/),
and I put a lengthy operation inside a timer (which
executes in separate thread).
Simple but effective.

Free a TThread either automatically or manually

I have a main thread and a separate thread in my program. If the separate thread finishes before the main thread, it should free itself automatically. If the main thread finishes first, it should free the separate thread.
I know about FreeOnTerminate, and I've read that you have to be careful using it.
My question is, is the following code correct?
procedure TMyThread.Execute;
begin
... Do some processing
Synchronize(ThreadFinished);
if Terminated then exit;
FreeOnTerminate := true;
end;
procedure TMyThread.ThreadFinished;
begin
MainForm.MyThreadReady := true;
end;
procedure TMainForm.Create;
begin
MyThreadReady := false;
MyThread := TMyThread.Create(false);
end;
procedure TMainForm.Close;
begin
if not MyThreadReady then
begin
MyThread.Terminate;
MyThread.WaitFor;
MyThread.Free;
end;
end;
You can simplify this to:
procedure TMyThread.Execute;
begin
// ... Do some processing
end;
procedure TMainForm.Create;
begin
MyThread := TMyThread.Create(false);
end;
procedure TMainForm.Close;
begin
if Assigned(MyThread) then
MyThread.Terminate;
MyThread.Free;
end;
Explanation:
Either use FreeOnTerminate or free the thread manually, but never do both. The asynchronous nature of the thread execution means that you run a risk of not freeing the thread or (much worse) doing it twice. There is no risk in keeping the thread object around after it has finished the execution, and there is no risk in calling Terminate() on a thread that has already finished either.
There is no need to synchronize access to a boolean that is only written from one thread and read from another. In the worst case you get the wrong value, but due to the asynchronous execution that is a spurious effect anyway. Synchronization is only necessary for data that can not be read or written to atomically. And if you need to synchronize, don't use Synchronize() for it.
There is no need to have a variable similar to MyThreadReady, as you can use WaitForSingleObject() to interrogate the state of a thread. Pass MyThread.Handle as the first and 0 as the second parameter to it, and check whether the result is WAIT_OBJECT_0 - if so your thread has finished execution.
BTW: Don't use the OnClose event, use OnDestroy instead. The former isn't necessarily called, in which case your thread would maybe continue to run and keep your process alive.
Have the main thread assign a handler to the worker thread's OnTerminate event. If the worker thread finishes first, then the handler can signal the main thread to free the thread. If the main thread finishes first, it can terminate the worker thread. For example:
procedure TMyThread.Execute;
begin
... Do some processing ...
end;
procedure TMainForm.Create;
begin
MyThread := TMyThread.Create(True);
MyThread.OnTerminate := ThreadFinished;
MyThread.Resume; // or MyThread.Start; in D2010+
end;
const
APPWM_FREE_THREAD = WM_APP+1;
procedure TMainForm.ThreadFinished(Sender: TObject);
begin
PostMessage(Handle, APPWM_FREE_THREAD, 0, 0);
end;
procedure TMainForm.WndProc(var Message: TMessage);
begin
if Message.Msg = APPWM_FREE_THREAD then
StopWorkerThread
else
inherited;
end;
procedure TMainForm.StopWorkerThread;
begin
if MyThread <> nil then
begin
MyThread.Terminate;
MyThread.WaitFor;
FreeAndNil(MyThread);
end;
end;
procedure TMainForm.Close;
begin
StopWorkerThread;
end;
No, your code is not good (though it probably will work in 99.99% or even 100% cases). If you are planning to terminate work thread from main thread, don't set FreeOnTerminate to True (I don't see what are you trying to gain in the above code by setting FreeOnTerminate to True, it at least makes your code less understandable).
A more important situation with terminating work threads is that you are trying to close an application while work thread is in wait state. The thread will not be awaken if you just call Terminate, generally you should use additional syncronization object (usually event) to wake up the work thread.
And one more remark - there is no need for
begin
MyThread.Terminate;
MyThread.WaitFor;
MyThread.Free;
end;
if you look at TThread.Destroy code, it calls Terminate and WaitFor, so
MyThread.Free;
is enough (at least in Delphi 2009, have no Delphi 7 sources at hand to check).
Updated
Read mghie answer. Consider the following situation (better on 1 CPU system):
main thread is executing
procedure TMainForm.Close;
begin
if not MyThreadReady then
begin
MyThread.Terminate;
MyThread.WaitFor;
MyThread.Free;
end;
end;
it checked MyThreadReady value (it is False) and was switched off by scheduler.
Now scheduler switches to work thread; it executes
Synchronize(ThreadFinished);
and forces scheduler to switch back to main thread. Main thread continues execution:
MyThread.Terminate; // no problem
MyThread.WaitFor; // ???
MyThread.Free;
can you say what will happen at WaitFor? I can't (requires a deeper look into TThread sources to answer, but at first glance looks like a deadlock).
Your real error is something different - you have written an unreliable code and trying to find out is it correct or not. That is bad practice with threads - you should learn to write a reliable code instead.
As for resources - when the TThread (with FreeOnTerminate = False) is terminated the only resources that remains allocated is Windows thread handle (it does not use substantial Windows resources after thread is terminated) and Delphi TThread object in memory. Not a big cost to be on the safe side.
Honestly, your
... Do some processing
Is the real problem here. Is that a loop for doing something recursively? If not and, instead, thats a huge task, you should consider split this task in small procedures / functions, and put all together in the execute body, calling one after another with conditional if's to know the thread state, like:
While not Terminated do
begin
if MyThreadReady then
DoStepOneToTaskCompletion
else
clean_and_or_rollback(Something Initialized?);
if MyThreadReady then
DoStepTwoToTaskCompletion
else
clean_and_or_rollback(Something Initialized?, StepOne);
if MyThreadReady then
DoStepThreeToTaskCompletion
else
clean_and_or_rollback(Something Initialized?, StepOne, StepTwo);
Self.DoTerminate; // Not sure what to expect from that one
end;
It is dirty, almost a hack, but will work as expected.
About FreeOnTerminate, well... just remove the declaration and always
FreeAndNil(ThreadObject);
I'm not a fan of syncronise. I like more critical sections, for the flexibility to extend the code to handle more shared data.
On the form public section, declare:
ControlSection : TRTLCriticalSection;
On form create or somewhere else before thread.create ,
InitializeCriticalSection(ControlSection);
Then, every time you write to a shared resource (including your MyThreadReady variable), do
EnterCriticalSection ( ControlSection );
MyThreadReady := True; //or false, or whatever else
LeaveCriticalSection ( ControlSection );
Before you go (exit), call
DeleteCriticalSection ( ControlSection );
and free your thread as you always do.
Regards
Rafael
I would state that mixing models is simply not recommended. You either use FreeOnTerminate and never touch the thread again, or you don't. Otherwise, you need a protected way for the two to communicate.
Since you want fine control over the thread variable, then don't use FreeOnTerminate. If your thread finishes early, clear the local resources that the thread has consumed as you normally would, and then simply let the main thread free the child thread when the application is finished. You'll get the best of both worlds - resources freed by the child thread as soon as it can be, and no worries about thread synchronization. (And it's got the added bonus of being much simpler in design/code/understanding/support...)

Resources