how to make delphi wait 30sec then continue - multithreading

I am trying to make an infinite loop but I want the loop to run every 30 seconds. The loop will start. A bunch of if statements take place and some information will be changed. The loop must then pause for 30 seconds and then the loop will start again. This must continue forever.
I am looking for a way to pause the loop for 30 seconds and then continue. Any good advice will be appreciated.
EDIT #1
The program shows "special" information based on date and time: As the time changes the information changes: 06:00 = math; 07:30 = biology. The program also shows you the time left until the next class starts. Thus the program needs to run continuously to update the time so that it knows exactly what period it is and how much time is left until the next period.
EDIT #2
I want put in a "refresh" so that script I want the script to be called on a set interval so that it is not running constantly and eating the ram. This interval must be 30 seconds.

Based on your update that provides more details I think I would use a single thread with a timer to provide a pulse to drive updates.
Set the timer interval to be whatever rate you wish updates to the GUI to occur at. For instance, perhaps a refresh rate of twice a minute is what you want, in which case set the timer interval to 30*1000.
Whenever the timer fires, use the current system time to work out the information that you need to display, and then display that information.
Note that this answer does not tell you how to wait 30 seconds and continue. However, I suspect that this is the easiest solution to your actual problem.
You don't want to block your program because that would stop the UI being responsive. It would stop you being able to interact with the UI and stop the UI from being able to paint itself. In a GUI program you must not block in the main thread. You should only block in background threads. But threads add complexity that is just needless. You don't want to block. You don't want to wait. You just need a regular pulse to drive updates. A timer.

If you have code that blocks the GUI, you can use a background thread and an event to provide a non blocking timer.
Create a new Forms application and put a TMemo component on your form.
This example will add a new line with the current time to your TMemo.
Main form:
unit u_frm_main;
interface
uses
u_workthread,
SysUtils,
Windows,
Forms,
SyncObjs, Classes, Controls, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
Worker : TWorkThread;
procedure ShowData;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ShowData;
begin
// do whatever you need to do here...
// show current time in memo
Memo1.Lines.Add(FormatDateTime('HH:NN:SS', Now));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// create our worker thread and start it
Worker := TWorkThread.Create(3, ShowData);
Worker.Start;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
// signal our worker thread that we are done here
Worker.ThreadEvent.SetEvent;
// terminate and wait
Worker.Terminate;
Worker.WaitFor;
end;
end.
Worker Thread:
unit u_workthread;
interface
uses
SysUtils,
SyncObjs,
Classes;
type
TWorkProc = procedure of object;
TWorkThread = class(TThread)
private
{ Private declarations }
Counter : Integer;
FTimeout : Integer;
FEventProc: TWorkProc;
procedure DoWork;
protected
procedure Execute; override;
public
ThreadEvent : TEvent;
constructor Create(TimeoutSeconds : Integer; EventProc: TWorkProc ); // timeout in seconds
destructor Destroy; override;
end;
implementation
procedure TWorkThread.DoWork;
begin
// put your GUI blocking code in here. Make sure you never call GUI elements from this procedure
//DoSomeLongCalculation();
end;
procedure TWorkThread.Execute;
begin
Counter := 0;
while not Terminated do
begin
if ThreadEvent.WaitFor(FTimeout) = wrTimeout then
begin
DoWork;
// now inform our main Thread that we have data
Synchronize(FEventProc);
end;
else
// ThreadEvent has been signaled, exit our loop
Break;
end;
end;
constructor TWorkThread.Create(TimeoutSeconds : Integer; EventProc: TWorkProc);
begin
ThreadEvent := TEvent.Create(nil, True, False, '');
// Convert to milliseconds
FTimeout := TimeoutSeconds * 1000;
FEventProc:= EventProc;
// call inherited constructor with CreateSuspended as True
inherited Create(True);
end;
destructor TWorkThread.Destroy;
begin
ThreadEvent.Free;
inherited;
end;
end.

Related

Delphi: Kill threads when application quits?

Background: I need to perform checks whether a bunch of network drives or remote computers are available. Since each DirectoryExists() needs a lot of time until a potential timeout, I perform the checks in separate threads. It can happen, that an end-user closes the application while some of the checks are still running. Since DirectoryExists() blocks, I have no chance of using the classical while not Terminated approach.
procedure TMyThread.Execute;
begin
AExists := DirectoryExists(AFilepath);
end;
Question 1: Is it a problem that some threads are still running when the application quits? Will Windows simply tidy up after me and that's it? Inside the IDE I get notification of un-freed objects, but outside IDE it just appears to be peaceful.
Question 2: Is it possible to terminate such simple threads with TerminateThread or is this potentially harmful in THIS case?
Question 3: I usually take the results from the threads in OnTerminate() event and let the threads FreeOnTerminate afterwards. If I wanted to free them myself, when should I do it? Can I free a thread in its OnTerminate event or is this a tiny bit too early? How would a thread inform me that it is done if not with OnTerminate?
Is it a problem that some threads are still running when the application quits?
Possibly, yes. It depends on what your code does after DirectoryExists() exits. You might end up trying to access things that no longer exist.
Will Windows simply tidy up after me and that's it?
To ensure everything is cleaned up properly, you are responsible for terminating your own threads. When the main VCL thread is done running, it will call ExitProcess(), which will forcibly terminate any secondary threads that are still running, which will not allow them to clean up after themselves, or notify any loaded DLLs that they are being detached from the threads.
Is it possible to terminate such simple threads with TerminateThread or is this potentially harmful in THIS case?
TerminateThread() is ALWAYS potentially harmful. NEVER use it.
I usually take the results from the Threads in OnTerminate() event and let the threads FreeOnTerminate afterwards.
That will not work if the main message loop has exited before the thread terminates. By default, the TThread.OnTerminate event is fired via a call to TThread.Synchronize(). Once the main message loop stops running, there won't be anything to process the pending Synchronize() requests, unless you run your own loop at app exit to call the RTL's CheckSynchronize() procedure until all of your threads have fully terminated.
if I wanted to free them myself, when should I do it?
Before your app wants to exit.
Can I free a thread in its OnTerminate event
No.
or is this a tiny bit too early?
That, and because it is always unsafe to free an object inside an event fired by that same object. The RTL still needs access to the object after the event handler exits.
That being said, since you don't have a clean way to terminate the threads safely, I suggest NOT allowing your app to exit when there are threads still running. When the user requests the app to exit, check if there are threads running, and if so then display a busy UI to the user, wait for all of the threads to terminate, and then exit the app.
For example:
constructor TMyThread.Create(...);
begin
inherited Create(False);
FreeOnTerminate := True;
...
end;
procedure TMyThread.Execute;
begin
...
if Terminated then Exit;
AExists := DirectoryExists(AFilepath);
if Terminated then Exit;
...
end;
type
TMainForm = class(TForm)
...
procedure FormClose(Sender: TObject; var Action: TCloseAction);
...
private
ThreadsRunning: Integer;
procedure StartAThread;
procedure ThreadTerminated(Sender: TObject);
...
end;
...
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ThreadsRunning = 0 then Exit;
// signal threads to terminate themselves...
if CheckWin32Version(6) then
ShutdownBlockReasonCreate(Handle, 'Waiting for Threads to Terminate');
try
// display busy UI to user ...
repeat
case MsgWaitForMultipleObjects(1, System.Classes.SyncEvent, False, INFINITE, QS_ALLINPUT) of
WAIT_OBJECT_0 : CheckSynchronize;
WAIT_OBJECT_0+1 : Application.ProcessMessages;
WAIT_FAILED : RaiseLastOSError;
end;
until ThreadsRunning = 0;
// hide busy UI ...
finally
if CheckWin32Version(6) then
ShutdownBlockReasonDestroy(Handle);
end;
end;
procedure TMainForm.StartAThread;
var
Thread: TMyThread;
begin
Thread := TMyThread.Create(...);
Thread.OnTerminate := ThreadTerminated;
Thread.Start;
Inc(ThreadsRunning);
end;
procedure TMainForm.ThreadTerminated(Sender: TObject);
begin
Dec(ThreadsRunning);
...
end;
Alternatively:
type
TMainForm = class(TForm)
...
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
...
private
ThreadsRunning: Integer;
WaitingForClose: Boolean;
procedure StartAThread;
procedure ThreadTerminated(Sender: TObject);
...
end;
...
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := (ThreadsRunning = 0);
if CanClose or WaitingForClose then Exit;
// signal threads to terminate themselves...
WaitingForClose := True;
// display busy UI to user ...
if CheckWin32Version(6) then
ShutdownBlockReasonCreate(Handle, 'Waiting for Threads to Terminate');
end;
procedure TMainForm.StartAThread;
var
Thread: TMyThread;
begin
Thread := TMyThread.Create(...);
Thread.OnTerminate := ThreadTerminated;
Thread.Start;
Inc(ThreadsRunning);
end;
procedure TMainForm.ThreadTerminated(Sender: TObject);
begin
Dec(ThreadsRunning);
...
if WaitingForClose and (ThreadsRunning = 0) then
begin
WaitingForClose := False;
// hide busy UI ...
if CheckWin32Version(6) then
ShutdownBlockReasonDestroy(Handle);
Close;
end;
end;
Is it a problem that some threads are still running when the application quits?
When taken literally, this question is a little bit malformed. That is because after ExitProcess is called, which is how a Delphi application is ended by default, no threads are running.
The answer to the question "is it a problem that some threads didn't have a chance to finish" depends on what these threads failed to complete. You would have to carefully analyze thread code, but generally speaking this might be prone to errors.
Will Windows simply tidy up after me and that's it? Inside the IDE I get notification of un-freed objects, but outside IDE it just appears
to be peaceful.
The OS will reclaim allocated memory when the process address space is destroyed, all object handles will be closed when the process handle table is destroyed, entry points of all loaded libraries will be called with DLL_PROCESS_DETACH. I can't find any documentation on this but I also presume pending IO requests would be called to cancel.
But all of this does not mean there won't be any problems. Things can get messy, for instance, involving interprocess communications or synchronization objects. Documentation for ExitProcess details one such example: if a thread vanishes before releasing a lock that one of the libraries tries to acquire while detaching, there's a deadlock. This blog post gives another specific example where the exiting process is forcibly terminated by the OS if a thread attempts to enter a critical section that is orphaned by another already terminated thread.
While it may make sense to let go of resource releasing at exit time, particularly if cleanup is taking a considerable amount of time, it is possible to get it wrong for a non-trivial application. A robust strategy is to clean up everything before ExitProcess is called. OTOH if you find yourself in a situation where ExitProcess is already called, such as the process is detaching from your dll because of termination, the nearly only safe thing to do is to leave everything behind and return - every other dll could have already been unloaded and every other thread terminated.
Is it possible to terminate such simple threads with TerminateThread or is this potentially harmful in THIS case?
TerminateThread is advised to be used only in most extreme cases but since the question has a bold "THIS" what the code really does should be examined. Looking at the RTL code we can see that the worst that can happen is leaving a file handle open which is accessed for reading only. THIS is not a problem at process termination time since the handle will be closed shortly.
I usually take the results from the threads in OnTerminate() event and let the threads FreeOnTerminate afterwards. If I wanted to free
them myself, when should I do it?
The only strict rule is after they are finished executing. The choice would probably be guided by the design of the application. What would be different is, you wouldn't be able to use FreeOnTerminate and you would keep references to your threads to be able to free them. In the test case I worked on for answering this question, the worker threads which are finished are freed when a timer fires, kind of like a garbage collector.
Can I free a thread in its OnTerminate event or is this a tiny bit too early?
Freeing an object in one of its own event handlers induces a risk of operating on freed instance memory. The documentation specifically warns against this for components but in general this is applicable to all classes.
Even if you'd want to disregard the warning, this is a deadlock. Although the handler is called after Execute returns, OnTerminate is still synchronized from the ThreadProc. If you attempt to free the thread in the handler, it will cause a wait from the main thread for the thread to finish - which is waiting for the main thread to return from OnTerminate, which is a deadlock.
How would a thread inform me that it is done if not with OnTerminate?
OnTerminate is fine for informing that a thread has done its job, although you can use other means like using synchronization objects or queuing a procedure or posting a message etc.. Also worth noting that it's possible to wait on a thread handle, which is what TThread.WaitFor does.
In my test program I tried to determine application termination time depending on various exit strategies. All test results are dependent on my testing environment.
Termination time is measured starting from when the OnClose handler of a VCL form is called and ending with just before ExitProcess is called by the RTL. Also, this method does not account for how long ExitProcess takes, which I presume would be different when there are dangling threads. But I didn't try to measure it anyway.
Worker threads query the existence of a directory on a non-existing host. This is the most I could come up on waiting time. Every query is on a new non-existing host, otherwise DirectoryExists returns immediately.
A timer starts and collects worker threads. Depending on the time the IO query takes (which is around 550ms) the timer interval effects the total count of threads at any given time. I tested on around 10 threads with a timer interval of 250ms.
Various debug outputs allow to follow the flow in the event log of the IDE.
My first test was to leave the worker threads behind - just quit the application. The time I measured was 30-65ms. Again, this could have caused ExitProcess itself to take longer.
Next, I tested terminating the threads with TerminateThread. This took 140-160ms. I believe this is actually closer to what the previous test would come up if the time ExitProcess takes could be accounted for. But I have no proof on that.
Next, I tested cancelling the IO request on running threads and then leaving them behind.This considerably decreased the amount of leaked memory, in fact completely eliminated in most of the runs. Although the cancellation request is asynchronous, nearly all of the threads return immediately and find the time to finish. Anyway, this took 160-190ms.
I should note here that the code in DirectoryExists is defective, at least in XE2. The first thing the function does is to call GetFileAttributes. An INVALID_FILE_ATTRIBUTES return denotes the function failed. This is how the RTL handles the fail:
function DirectoryExists(const Directory: string; FollowLink: Boolean = True): Boolean;
...
...
Result := False;
Code := GetFileAttributes(PChar(Directory));
if Code <> INVALID_FILE_ATTRIBUTES then
begin
...
end
else
begin
LastError := GetLastError;
Result := (LastError <> ERROR_FILE_NOT_FOUND) and
(LastError <> ERROR_PATH_NOT_FOUND) and
(LastError <> ERROR_INVALID_NAME) and
(LastError <> ERROR_BAD_NETPATH);
end;
end;
This code assumes that unless GetLastError returns one of the above error codes the directory exists. This reasoning is flawed. Indeed, when you cancel the IO request, GetLastError returns ERROR_OPERATION_ABORTED (995) as documented but DirectoryExists returns true whether the directory exists or not.
Waiting for the threads to finish without cancelling IO takes 330-530ms. This completely eliminates memory leaks.
Cancelling IO requests and then waiting for the threads to finish takes 170-200ms. Of course no memory leaks here either. Considering there are no significant timing difference in any of the options, this would be the one I choose.
Testing code I used is below:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes,
Vcl.Controls, Vcl.Forms, Vcl.ExtCtrls,
generics.collections;
type
TForm1 = class(TForm)
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormDestroy(Sender: TObject);
private
FThreads: TList<TThread>;
end;
var
Form1: TForm1;
implementation
uses
diagnostics;
{$R *.dfm}
type
TIOThread = class(TThread)
private
FTarget: string;
protected
constructor Create(Directory: string);
procedure Execute; override;
public
destructor Destroy; override;
end;
constructor TIOThread.Create(Directory: string);
begin
FTarget := Directory;
inherited Create;
end;
destructor TIOThread.Destroy;
begin
inherited;
OutputDebugString(PChar(Format('Thread %d destroyed', [ThreadID])));
end;
procedure TIOThread.Execute;
var
Watch: TStopwatch;
begin
OutputDebugString(PChar(Format('Thread Id: %d executing', [ThreadID])));
Watch := TStopwatch.StartNew;
ReturnValue := Ord(DirectoryExists(FTarget));
Watch.Stop;
OutputDebugString(PChar(Format('Thread Id: %d elapsed time: %dms, return: %d',
[ThreadID, Watch.Elapsed.Milliseconds, ReturnValue])));
end;
//-----------------------
procedure TForm1.FormCreate(Sender: TObject);
begin
FThreads := TList<TThread>.Create;
Timer1.Interval := 250;
Timer1.Enabled := True;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FThreads.Free;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
ShareName: array [0..12] of Char;
i: Integer;
H: THandle;
begin
for i := FThreads.Count - 1 downto 0 do
if FThreads[i].Finished then begin
FThreads[i].Free;
FThreads.Delete(i);
end;
for i := Low(ShareName) to High(ShareName) do
ShareName[i] := Chr(65 + Random(26));
FThreads.Add(TIOThread.Create(Format('\\%s\share', [string(ShareName)])));
OutputDebugString(PChar(Format('Possible thread count: %d', [FThreads.Count])));
end;
var
ExitWatch: TStopwatch;
// not declared in XE2
function CancelSynchronousIo(hThread: THandle): Bool; stdcall; external kernel32;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i: Integer;
Handles: TArray<THandle>;
IOPending: Bool;
Ret: DWORD;
begin
ExitWatch := TStopwatch.StartNew;
// Exit;
Timer1.Enabled := False;
{
for i := 0 to FThreads.Count - 1 do
TerminateThread(FThreads[i].Handle, 0);
Exit;
//}
if FThreads.Count > 0 then begin
SetLength(Handles, FThreads.Count);
for i := 0 to FThreads.Count - 1 do
Handles[i] := FThreads[i].Handle;
//{
OutputDebugString(PChar(Format('Cancelling at most %d threads', [Length(Handles)])));
for i := 0 to Length(Handles) - 1 do
if GetThreadIOPendingFlag(Handles[i], IOPending) and IOPending then
CancelSynchronousIo(Handles[i]);
//}
//{
Assert(FThreads.Count <= MAXIMUM_WAIT_OBJECTS);
OutputDebugString(PChar(Format('Will wait on %d threads', [FThreads.Count])));
Ret := WaitForMultipleObjects(Length(Handles), #Handles[0], True, INFINITE);
case Ret of
WAIT_OBJECT_0: OutputDebugString('wait success');
WAIT_FAILED: OutputDebugString(PChar(SysErrorMessage(GetLastError)));
end;
//}
for i := 0 to FThreads.Count - 1 do
FThreads[i].Free;
end;
end;
procedure Exiting;
begin
ExitWatch.Stop;
OutputDebugString(PChar(
Format('Total exit time:%d', [ExitWatch.Elapsed.Milliseconds])));
end;
initialization
ReportMemoryLeaksOnShutdown := True;
ExitProcessProc := Exiting;
end.

Why does it take 100ms to wait for a TThread on Mac OS?

I see in my application that every thread I'm running takes around a 100ms to get finished even though there is nothing to do in the thread itself.
See this sample:
program threadtest;
uses
cThreads, SysUtils, Classes;
type
TSampleThread = class(TThread)
protected
procedure Execute; override;
end;
var
Thread: TThread;
I: Integer;
procedure TSampleThread.Execute;
begin
// Nothing
end;
begin
WriteLn(TimeToStr(Now) + ' Start');
for I := 0 to 99 do
begin
Thread := TSampleThread.Create(True);
// Thread.Start; // We don't need to start the thread.
Thread.Free; // This call takes around a 100ms
end;
WriteLn(TimeToStr(Now) + ' Finished');
end.
The output is
23:08:17 Start
23:08:28 Finished
As you can see the loop takes around 10 seconds to finish. The call to Free (respectively the inner call to WaitFor) takes over 100ms.
I don't see this problem on Windows. Why is this happening on Mac OS? How can I do it faster?

Delphi - terminate thread after single successful execution or by user cancellation

New here. Relatively new to Delphi as well so plz be kind...
My actual (domain) problem: small VCL app that communicates with two laboratory balances via serial, balances output weight readings on a continuous 1-second interval, said weighs are displayed in the captions of two labels. When user clicks a 'Weigh' button, I need to wait for a valid weight (stable, within range, etc.) and record said weight once, -or-, allow the user to cancel the weighing.
My problem as implemented. Creating a separate thread when user clicks weigh button using TEvent template from S.MAHDI / David Heffernan as shown in this post.
TWeigh = class(TThread)
private
FTerminateEvent: TEvent;
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
constructor Create(ACreateSuspended: Boolean);
destructor Destroy; override;
end;
constructor TWeigh.Create(ACreateSuspended: Boolean);
begin
FTerminateEvent := TEvent.Create(nil, True, False, '');
inherited;
end;
destructor TWeigh.Destroy;
begin
inherited;
FTerminateEvent.Free;
end;
procedure TWeigh.TerminatedSet;
begin
FTerminateEvent.SetEvent;
Beep;
end;
procedure TWeigh.Execute();
begin
while (not Terminated) do begin
if (validweight) then begin
Synchronize(procedure begin
DoStuff();
end);
end;
FTerminateEvent.WaitFor(100);
end;
end;
My form button click event looks like:
{ Weigh is global implementation var of class TWeigh }
procedure TForm1.btnWeighClick(Sender: TObject);
var
B : TButton;
begin
B := Sender as TButton;
if (B.Caption = 'Weigh') then Weigh := TWeigh.Create(False);
if (B.Caption = 'Cancel') then Weigh.Free;
B.Caption := Trim(Copy('CancelWeigh ',AnsiPos(B.Caption,'Weigh Cancel'),6));
end;
This appears to work fine for the cancellation requirement. It's my understanding that Synchronize messages the main thread and it is the main thread that executes the anonymous procedure containing DoStuff(), so there should be no race conditions between the user clicking cancel and a valid weight coming in. (Right?)
I'm stuck on how to have the weigh thread only execute a single time. Various solutions I've tried have resulted in deadlocks (add Weigh.Free to DoStuff()... didn't take long to figure out why THAT doesn't work), single execution but non-free'd threads (self.Terminate after the synchronize section within the if block), or various other nonsense.
So, is it even possible to have this thread free and/or kill itself while still allowing for the parent thread via user input to kill it, or do I need a completely different architecture for this?
Edit in response to why a loop: I only need a single reading, but the time until I get that single reading varies between immediately and never. The balances can take several seconds to stabilize, during which time unstable readings are read and displayed every second. The ability for the user to cancel is still required because the reading might never be valid (under-overweight).
If I understand correctly, you wish to quit the thread when you've finished calling DoStuff. That can be done like so:
procedure TWeigh.Execute();
begin
while (not Terminated) do begin
if (validweight) then begin
Synchronize(procedure begin
DoStuff();
end);
exit;
end;
FTerminateEvent.WaitFor(100);
end;
end;
I have to say that this looks more appropriate for a timer than a thread. All the work is done on the main thread, and the thread just appears to be there to check a flag at a regular interval. That sounds like a timer. In fact, why even a timer? Why not fire the DoStuff when you set the flag true?

Recreating a TThread Inside a TThread dervied class

I created a new class derived from TThread class, and on the constructor i call "inherited Create(True);", and then call "Resume()" since i have override the Execute() call, now i wanna recall the Execute() (Run the Thread Again) without destroying the class instance, so i have a function inside the new class called "myRestart()", which recalls "inherited Create(True);" and makes me able to call "Resume()" again and thread works again.
my question is, is this a safe practice? will it work also if i have multiple instances of this class? or is there a better way to do it?
thanks
Don't go around doing things like that. If you want procedures/functions in your thread class to run more than once, call them from a while() loop in your Execute override and signal the thread to run the code with a suitable synchro object at the top, a semaphore or event, say:
TmyThread.Execute;
begin
while true do
begin
someEvent.waitFor(INFINITE);
if terminated then exit;
doMyProcedure(params);
doOtherStuff;
end;
end;
I think you must show your Restart Code?
Because as I know if the thread finish it's Execute procedure then It's state in OS will change to DONE and calling resume again only start that thread as just a function in main thread not a real separate thread.
by the way you can use this sample code for your need
unit UWorker;
interface
uses Windows, Classes, Contnrs;
type
TWorkerThread=class;
TWorkerJob=class
procedure ExecuteJob(Worker: TWorkerThread); virtual; abstract;
end;
TWorkerThread=class(TThread)
private
FFinished: TObjectList;
FNotFinished: TObjectList;
protected
procedure Execute;Override;
public
constructor Create(createSuspended: Boolean);override;
destructor Destroy; override;
public
property Finished: TObjectList read FFinished;
property NotFinished: TObjectList read FNotFinished;
end;
implementation
{ TWorkerThread }
constructor TWorkerThread.Create(createSuspended: Boolean);
begin
inherited;
FFinished := TObjectList.Create;
FNotFinished := TObjectList.Create;
end;
destructor TWorkerThread.Destroy;
begin
FFinished.Free;
FNotFinished.Free;
inherited;
end;
procedure TWorkerThread.Execute;
var
CurrentJob: TWorkerJob;
begin
while not Terminated do
begin
if FNotFinished.Count > 0 then
begin
CurrentJob := TWorkerJob(FNotFinished.Items[0]);
FNotFinished.Extract(CurrentJob);
with CurrentJob do
begin
ExecuteJob(Self);
end;
FFinished.Add(CurrentJob);
end else
begin
// pass the cpu to next thread or process
Sleep(5);
end;
end;
end;
end.
for use this code just create a worker and then create some instance of jobs and add them to NotFinished list. the Worker will execute all jobs one by one.
To restart a job just extract it from Finished list and add it again to the NotFinished.
remember you must inherit your jobs and override the ExecuteJob procedure.

Which wait method to call in an infinite waiting thread for Delphi XE2

if I've got a
While not terminated do
begin
doStuff;
end
loop in the execute method of a Delphi XE2 thread, and I want to not make it bogart all my flops.
What should I call,
in Delphi 7, it was easy, I'd call Sleep(X) where X was inversely proportional to how interesting I thought the thread was.
But now, I've got
SpinWait(X);
Which calls YieldProcessor X number of times
and
Yield;
which calls the windows function "SwitchToThread".
Should I use any of these or should I just set the priority of the thread?
SpinWait wastes time without giving up the processor. It's like Sleep, but without yielding control to any other threads during the delay. If you don't have multiple cores, then it's a total waste because no other thread can do anything while you're spinning. As far as I can tell, Yield is analogous to Sleep(0), except that if there is no other thread ready to run, then the calling thread just continues immediately.
Neither of those sounds like what you want if you know that your thread really has nothing else to do.
The best solution would be to find or establish some waitable object (like a semaphore, event, or process handle) that you could wait to become signaled. Then you wouldn't have to bother waking up at all, just so you can poll your status and go to sleep again.
Threadpool example:
unit ThreadPool;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, contnrs, syncobjs;
type
TpooledTask=class(TObject)
private
FonComplete:TNotifyEvent;
protected
Fparam:TObject;
procedure execute; virtual; abstract;
public
constructor create(onComplete:TNotifyEvent;param:TObject);
end;
TThreadPool=class(TObjectQueue)
private
access:TcriticalSection;
taskCounter:THandle;
threadCount:integer;
public
constructor create(initThreads:integer);
procedure addTask(aTask:TpooledTask);
end;
TpoolThread=class(Tthread)
private
FmyPool:TThreadPool;
protected
procedure Execute; override;
public
constructor create(pool:TThreadPool);
end;
implementation
{ TpooledTask }
constructor TpooledTask.create(onComplete: TNotifyEvent; param: TObject);
begin
FonComplete:=onComplete;
Fparam:=param;
end;
{ TThreadPool }
procedure TThreadPool.addTask(aTask: TpooledTask);
begin
access.acquire;
try
push(aTask);
finally
access.release;
end;
releaseSemaphore(taskCounter,1,nil); // release one unit to semaphore
end;
constructor TThreadPool.create(initThreads: integer);
begin
inherited create;
access:=TcriticalSection.create;
taskCounter:=createSemaphore(nil,0,maxInt,'');
while(threadCount<initThreads) do
begin
TpoolThread.create(self);
inc(threadCount);
end;
end;
{ TpoolThread }
constructor TpoolThread.create(pool: TThreadPool);
begin
inherited create(true);
FmyPool:=pool;
FreeOnTerminate:=true;
resume;
end;
procedure TpoolThread.execute;
var thisTask:TpooledTask;
begin
while (WAIT_OBJECT_0=waitForSingleObject(FmyPool.taskCounter,INFINITE)) do
begin
FmyPool.access.acquire;
try
thisTask:=TpooledTask(FmyPool.pop);
finally
FmyPool.access.release;
end;
thisTask.execute;
if assigned(thisTask.FonComplete) then thisTask.FonComplete(thisTask);
end;
end;
end.

Resources