Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A question of threads

1 view
Skip to first unread message

Paul

unread,
Aug 11, 2006, 7:01:38 AM8/11/06
to
Hi All,

Can anyone tell me how I can create a thread when a program is first run,
use that thread to run a function every few minutes, and then destory the
thread when the program ends.

Cheers,
Paul


Martin James

unread,
Aug 11, 2006, 7:36:12 AM8/11/06
to

--------------------------------------
TeveryFewMinutesThread=class(TThread)
private
FdelayMS:integer;
FwaitEvent:TsimpleEvent;
function MyFunction:integer;
protected
procedure execute; override;
public
constructor create(everyFewMinutes:integer);
procedure terminate; reintroduce;
end;

function TeveryFewMinutesThread.MyFunction:integer;
begin
blahBlah;
result:=0;
end;

constructor TeveryFewMinutesThread.create(everyFewMinutes);
begin
inherited create(true);
freeOnTerminate:=true;
FwaitEvent:=TsimpleEvent.create;
FdelayMS:=1000*60*everyFewMinutes;
resume;
end;

procedure terminate;
begin
FwaitEvent.setEvent;
end;

procedure TeveryFewMinutesThread.execute;
begin
try
while(wrTimeout=FwaitEvent.waitFor(FdelayMS) do MyFunction;
finally
FwaitEvent.free;
end;
end;
--------------------------------------


Rgds,
Martin

Liz

unread,
Aug 11, 2006, 7:45:24 AM8/11/06
to
Paul wrote:

Create your thread object, I'd use a timer within it, possibly not the
best, so in the threads definition add a TTimer, a variable to say dont
stop yet, and a procedure to call to say stop .

then, in the execute, create the timer, if you cant fail and stop
obviously otherwise, set the ontimer procedure to do whatever it is you
need to do, then set the timer going. and while not stopping yet
sleep(1); or something and finally clear up the timer.

Then in the stop procedure set the stopping variable to true.

now in your app in the mainform create say create the thread, and in
the clean up, call the threads stop procedure.

--
Liz the Brit
Delphi things I have released: http://www.xcalibur.co.uk/DelphiThings

Paul

unread,
Aug 11, 2006, 7:40:12 AM8/11/06
to
Hi Martin,

thanks very much for the code. I really appreciate it. How do I call this or
start it from my main form ?

Cheers,
Paul

"Martin James" <nos...@dial.pipex.com> wrote in message
news:44dc...@newsgroups.borland.com...

JD

unread,
Aug 11, 2006, 8:26:55 AM8/11/06
to

Martin James <nos...@dial.pipex.com> wrote:
>
> [...]

>procedure TeveryFewMinutesThread.execute;
>begin
> try
> while(wrTimeout=FwaitEvent.waitFor(FdelayMS) do MyFunction;
> finally
> FwaitEvent.free;
> end;
>end;
>--------------------------------------

Exactly how would you expect this thread to ever be terminated
by the main thread?

~ JD

Yusuf celik

unread,
Aug 11, 2006, 8:50:07 AM8/11/06
to

Hi,
Just an idea
can we use Sleep instead of TSimpleEvent as follows ?

procedure TeveryFewMinutesThread.execute;
begin
try
while(not Terminated) do
begin
Sleep(FdelayMS);
MyFunction;
end;
finally
FwaitEvent.free;
end;
end;

Regards
Yusuf

JD

unread,
Aug 11, 2006, 8:53:03 AM8/11/06
to

"Paul" <pa...@pacsoftware.com.au> wrote:
>
> Can anyone tell me how I can create a thread when a program
> is first run,

Create it in the Main Form's OnCreate event.

> use that thread to run a function every few minutes,

You really haven't provided enough information as to what
this function is to do (you may very well want to use a
Timer instead).

In any event, you *do not* want to use TSimpleEvent.WaitFor
as Martin suggested because even if coded correctly the
application may be delayed in shutting down for as long as
the interval set for your threaded function.

The thread's Execute method needs to check the thread's
Terminated property so that it can know if it should break
out of waiting and allow the application to close. This can
be accomplished with a simple loop that calls GetTickCount
to increment a variable that is compared to the desired wait
interval. If it's not time to run your function, call Sleep
for a short interval and then loop. You should also be
checking Terminated inside your function as well.

> and then destory the thread when the program ends.

Destroy it in the Main Form's OnDestroy event by calling it's
Terminate method and then it's WaitFor method and do not set
FreeOnTerminate to true as Martin also suggested.

~ JD

Martin James

unread,
Aug 11, 2006, 9:05:03 AM8/11/06
to
Paul wrote:
> Hi Martin,
>
> thanks very much for the code. I really appreciate it. How do I call this or
> start it from my main form ?

-----------------------------------------
TForm1 = class(TForm)
<Delphi components>
private
myIntervalThread:TeveryFewMinutesThread;
public
{ Public declarations }
end;
..
..
procedure TForm1.FormCreate(Sender: TObject);
begin
// Do something every five minutes
myIntervalThread:=TeveryFewMinutesThread.create(5);
end;
-----------------------------------------

A very simplistic way of getting rid of it at app close is in an
OnCloseQuery handler:

-----------------------------------------------------------------------
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
myIntervalThread.terminate;
sleep(10); // allow the thread to go away.
end;
-----------------------------------------------------------------------

A more solid way of ensuring that the secondary thread is terminated is
to post a message as the last line of the thread and use this to close
the main form. I did not want to complicate my simple example code, so
I did not add this. Nor did I bother to raise the priority of the
secondary thread in the terminate method.

Delphi provides other ways of, (supposedly cleanly), terminating/freeing
up threads, eg. TThread.waitFor and OnTerminate handlers. IMHO, these
are best avoided as they are hard-sync, non-queued waits. Such
inter-thread comms mechanisms just invite deadlocks and/or unnecessary
main-thread involvement in things the main thread should not be involved in.


Rgds,
Martin

Martin James

unread,
Aug 11, 2006, 8:46:16 AM8/11/06
to
>
> Exactly how would you expect this thread to ever be terminated
> by the main thread?
>

Err.. by calling TeveryFewMinutesThread.terminate. OK, OK, so I forgot
to make the terminate procedure a method when quickly typing in my
example code. It's pretty obviously supposed to be a method since it's
declared as one. Anyway, for completeness, I meant:

-------------------------------------------
procedure TeveryFewMinutesThread.terminate;
begin
FwaitEvent.setEvent;
end;
-------------------------------------------

rather than:

-------------------------------------------


procedure terminate;
begin
FwaitEvent.setEvent;
end;

-------------------------------------------


If you want to be pedantic, there's lots of other stuff I could have
added, eg. raising the priority of the thread to tpTimeCritical in
'terminate' to try and ensure it preempts the main thread and frees all
its stuff before the main thread exits, or providing a PostMessaged
termination notification as the last line, or a P-C queue with a
transaction class that contains the function with parameters, results
and errorMessage fields, but over-complex example code often does not
help.

It's often better to just give some simple example and, if there is a
further problem, or deeper requirement, the OP can refine their query in
a later post. I'm half-expecting 'but I want my function result in the
main thread for display' <g>

Rgds,
Martin

JD

unread,
Aug 11, 2006, 8:59:45 AM8/11/06
to

"Yusuf celik" <y...@yus.yus> wrote:
>
> can we use Sleep instead of TSimpleEvent as follows ?

No. Not if you want the application to not close until it
has slept FdelayMS or you want a memory leak or AV. See my
other reply in this thread.

> finally
> FwaitEvent.free;

No need to free it if you don't need to create it.

~ JD

Martin James

unread,
Aug 11, 2006, 9:21:09 AM8/11/06
to
>
> In any event, you *do not* want to use TSimpleEvent.WaitFor
> as Martin suggested because even if coded correctly the
> application may be delayed in shutting down for as long as
> the interval set for your threaded function.

Look at my code again, this time ,without the 'Borland Blinkers' on <g>

> The thread's Execute method needs to check the thread's
> Terminated property

Why? Setting a boolean flag is only of any use if the thread is
actually running and can notice the flag. If the thread is not
ready/running, it will not see the flag. Such a thread has to be
signaled to make it ready, and then running, so it can exit and
terminate itself.

so that it can know if it should break
> out of waiting and allow the application to close. This can
> be accomplished with a simple loop that calls GetTickCount
> to increment a variable that is compared to the desired wait
> interval.

Oh dear...

If it's not time to run your function, call Sleep
> for a short interval and then loop.

Nope. Avoidable waste of CPU.

You should also be
> checking Terminated inside your function as well.

If the function takes a long time, then yes, an 'abort' boolean in the
thread that is periodically checked inside your function loops is a good
idea. That's assuming your function is CPU-intensive. If, OTOH, it is
making blocking calls, you may have to make other arrangements to ensure
that a blocking call returns early and allow a prompt termination, eg.
closing sockets, creating a temporary file, whatever is needed to
*singal* the thread to become ready, then running, and then terminated/dead.

>> and then destory the thread when the program ends.
>
> Destroy it in the Main Form's OnDestroy event by calling it's
> Terminate method and then it's WaitFor method and do not set
> FreeOnTerminate to true as Martin also suggested.

Oh dear...

Using TThread.waitFor is one of the primary reasons for 'My application
will not shut down' posts and 'ThreadFunk'- 'How do I do this without
using threads'. Similarly, TThread.synchronize, similarly,
TThread.OnTerminate.

All these inter-thread comms mechanisms are flawed because they are
hard-sync, ie. deadlock-generators.

Rgds,
Martin

JD

unread,
Aug 11, 2006, 11:40:24 AM8/11/06
to

Martin James <nos...@dial.pipex.com> wrote:
>
> Look at my code again, this time ,without the 'Borland
> Blinkers' on <g>

I have and see that sooner or later ... it will fail.

>> The thread's Execute method needs to check the thread's
>> Terminated property
>
> Why? Setting a boolean flag is only of any use if the thread
> is actually running and can notice the flag.

If the Execute method is being executed, indeed the thread is
running.

> If the thread is not ready/running, it will not see the
> flag.

It doesn't need to see it when it's not running.

> Such a thread has to be signaled to make it ready,

That would be the call to Resume in the Create method.

>> If it's not time to run your function, call Sleep for a
>> short interval and then loop.
>
>Nope. Avoidable waste of CPU.

Unless you use a TCriticalSection or similar method, you
can't avoid it and blocking can be even more exspensive.
Using TSimpleEvent.WaitFor blocks the thread until signaled.
Your solution is to use a procedure which calls SetEvent and
which breaks the loop which in turn causes the Execute method
to fall through and the thread is Terminated.

Sooner or later ... this will fail because the procedure is
called within the context of the main thread. This means that
you are accessing FWaitEvent from within the context of the
main thread AND the worker thread. IOW, Concurrent Access (aka
Race Condition).

>> You should also be checking Terminated inside your function
>> as well.
>
> If the function takes a long time, then yes, an 'abort'
> boolean in the thread that is periodically checked inside
> your function loops is a good idea.

It's a good idea period. The system that I use most often is a
P4 2.0 GHZ and it irritates me when an application takes
several seconds to shut down.

>> Destroy it in the Main Form's OnDestroy event by calling it's
>> Terminate method and then it's WaitFor method and do not set
>> FreeOnTerminate to true as Martin also suggested.
>

> Using TThread.waitFor is one of the primary reasons for 'My
> application will not shut down' posts and 'ThreadFunk'- 'How
> do I do this without using threads'.

What's your point? These groups are full of posts where
individuals have not understood how to use something and
or misused them.

> All these inter-thread comms mechanisms are flawed because
> they are hard-sync, ie. deadlock-generators.

Just because one doesn't understand how to correctly implement
their use doesn't mean that they are flawed. In deed, when
they fail, it's the programmers logic that is flawed - not
TThread.

~ JD

Martin James

unread,
Aug 11, 2006, 1:01:43 PM8/11/06
to

> I have and see that sooner or later ... it will fail.

Why?

>>> The thread's Execute method needs to check the thread's
>>> Terminated property
>> Why? Setting a boolean flag is only of any use if the thread
>> is actually running and can notice the flag.
>
> If the Execute method is being executed, indeed the thread is
> running.

The thread can be running, ready, suspended, waiting, etc. etc.

It can only terminate itself if it can be made running. If it is
suspended, waiting, timing out a sleep() call etc, it is not running.
If it is not running, it cannot notice any flags.

>> If the thread is not ready/running, it will not see the
>> flag.
>
> It doesn't need to see it when it's not running.

Yes it does. If it is waiting, it *must be signaled to become ready,
and then running*, before it can terminate itself.

>> Such a thread has to be signaled to make it ready,
>
> That would be the call to Resume in the Create method.

Suspended is only one state in which execution is not being applied. If
the thread is not in the running state for whatever reason, it cannot
terminate itself no matter how many simple flags you set. If it is
waiting on some OS synchro object or blocking call, it has to be
*signaled via the OS* to become ready/running. ** Inter-thread
signaling via OS kernel synchro API calls is guaranteed thread-safe **

>>> If it's not time to run your function, call Sleep for a
>>> short interval and then loop.
>> Nope. Avoidable waste of CPU.
>
> Unless you use a TCriticalSection or similar method, you
> can't avoid it and blocking can be even more exspensive.

Eh? OS synchro calls do not need any protection. Events, semaphores
and mutexes are absolutely thread-safe. They just cannot not be.

> Using TSimpleEvent.WaitFor blocks the thread until signaled.
> Your solution is to use a procedure which calls SetEvent and
> which breaks the loop which in turn causes the Execute method
> to fall through and the thread is Terminated.
>
> Sooner or later ... this will fail because the procedure is
> called within the context of the main thread. This means that
> you are accessing FWaitEvent from within the context of the
> main thread AND the worker thread. IOW, Concurrent Access (aka
> Race Condition).

TsimpleEvent is a light wrapper around an OS event. The event is a
kernel synchro object and is surely thread-safe - the whole point of OS
synchro objects is that they can be signaled from multiple threads:

-----------------------------------

TEvent = class(THandleObject)
public
constructor Create(EventAttributes: PSecurityAttributes; ManualReset,
InitialState: Boolean; const Name: string);
function WaitFor(Timeout: DWORD): TWaitResult;
procedure SetEvent;
procedure ResetEvent;
end;


{ TSimpleEvent }

constructor TSimpleEvent.Create;
begin
FHandle := CreateEvent(nil, True, False, nil); // ** OS SYNCHRO API
end;
..
function TEvent.WaitFor(Timeout: DWORD): TWaitResult;
begin
case WaitForSingleObject(Handle, Timeout) of //** OS SYNCHRO API
WAIT_ABANDONED: Result := wrAbandoned;
WAIT_OBJECT_0: Result := wrSignaled;
WAIT_TIMEOUT: Result := wrTimeout;
WAIT_FAILED:
begin
Result := wrError;
FLastError := GetLastError;
end;
else
Result := wrError;
end;
end;


----------------------------------


>>> You should also be checking Terminated inside your function
>>> as well.
>> If the function takes a long time, then yes, an 'abort'
>> boolean in the thread that is periodically checked inside
>> your function loops is a good idea.
>
> It's a good idea period.

If the function is short enough so that it's run time is not
human-noticeable, why bother?

The system that I use most often is a
> P4 2.0 GHZ and it irritates me when an application takes
> several seconds to shut down.

Several seconds? That's surely too long, yes. Threads that take seconds
to terminate are badly designed. Milliseconds is more like it, at the most.


>>> Destroy it in the Main Form's OnDestroy event by calling it's
>>> Terminate method and then it's WaitFor method and do not set
>>> FreeOnTerminate to true as Martin also suggested.
>> Using TThread.waitFor is one of the primary reasons for 'My
>> application will not shut down' posts and 'ThreadFunk'- 'How
>> do I do this without using threads'.
>
> What's your point? These groups are full of posts where
> individuals have not understood how to use something and
> or misused them.

Yes, and some things are just so easy to misuse. Unfortunately,
hard-sync inter-thread comms falls right in the middle of that category.

>> All these inter-thread comms mechanisms are flawed because
>> they are hard-sync, ie. deadlock-generators.
>
> Just because one doesn't understand how to correctly implement
> their use doesn't mean that they are flawed. In deed, when
> they fail, it's the programmers logic that is flawed - not
> TThread.

<sigh> When a multiThreaded app using hard-sync becomes more complex,
the number of possible paths through the threads, and the combinatorial
explosion of possible states, becomes err.. 'very difficult' to
predict and so the number of deadlock-possibilities rapidly becomes very
large - so large that they are almost impossible to predict, never mind
to test for. Sure, there is a design of locking that will work under
all circumstances, all loadings and all misuse, but no-one knows what it is.

Better to not bother to try and use asynchronous, queued comms.

Rgds,
Martin

JD

unread,
Aug 11, 2006, 11:22:19 PM8/11/06
to

Martin James <nos...@dial.pipex.com> wrote:
>
>> If the Execute method is being executed, indeed the thread is
>> running.
>
>The thread can be running, ready, suspended, waiting, etc. etc.

Now you're introducing behavior that wasn't part of the
original design so I'm just going to skip this.

>> this will fail because [...] Race Condition.


>
> TsimpleEvent is a light wrapper around an OS event. The
> event is a kernel synchro object and is surely thread-safe

I conceed the usage of TSimpleEvent. I wasn't at a system
that had the VCL source installed and we all know that VCL
objects aren't thread safe so ... Not an excuse - just an
explaination. I should have waited.

~ JD

Martin James

unread,
Aug 12, 2006, 4:35:38 AM8/12/06
to
JD wrote:
> Martin James <nos...@dial.pipex.com> wrote:
>>> If the Execute method is being executed, indeed the thread is
>>> running.
>> The thread can be running, ready, suspended, waiting, etc. etc.

> Now you're introducing behavior that wasn't part of the
> original design so I'm just going to skip this.

It was, since the OS holds the thread state. The state is not totally
under the control of the user thread code. Electing to wait on a kernel
synchro object is one of those that is, and is a valid and safe way of
generating a timeout interval that can be terminated early by another
thread.

The thread can certainly be suspended, since it is during construction.
When resumed, it becomes ready. It may not run immediately because there
are more ready/running threads than processors and so it could remain
ready. When a processor becomes available to run it, it will be
dispatched on a processor and so become running. When it hits the event
wait, it leaves running and enters waiting, (its thread descriptor
reference queued up to both the the event object and timer queue, the
thread receiving no CPU). When the event is signaled by another thread,
(eg main thread), it becomes read again and, if a processor is
available, running. If no signal is received, the event wait times out
anyway and the thread becomes becomes ready/waiting. While the function
is being run, the thread by be interrupted by a driver that makes a
higher-priority thread ready and so causes preemption of 'our' thread -
forces it out of running into ready to make a processor available to run
the higher-priority thread. 'Our' thread will run again when a processor
again becomes available to run it.

Many of these events and state transitions are not under the control of
the thread under consideration, nevertheless, they may happen and they
may, or may not, influence the functionality of your thread. An extreme
example is if some developer introduces a bug into a real-time priority
thread that causes it to CPU-loop continuously. If the system has only
one processor, your thread will never run, nor will the main thread, nor
will Firefox, Word or the Delphi IDE. The task-manager may not run.
The box may need a power-cycle to recover.


>>> this will fail because [...] Race Condition.
>> TsimpleEvent is a light wrapper around an OS event. The
>> event is a kernel synchro object and is surely thread-safe
>
> I conceed the usage of TSimpleEvent. I wasn't at a system
> that had the VCL source installed and we all know that VCL
> objects aren't thread safe so ... Not an excuse - just an
> explaination. I should have waited.

<g> one problem is that a lot of Borland stuff has no indication of
'thredsafeness', so occasionally requiring some digging to see what is
Borland VCL and what is simple reentrant code and/or thrad-safe API
calls, and what is a VCL operation on non-thread-safe data.

Another problem is that the Borland thread examples, and Borland thread
support in general, is not exactly of a high a quality as, say, the
compiler. This often obliges developers to make use of direct API calls
to implement inter-thread comms in an efficient and effective manner.

Critical section, semaphore, event, mutex calls are all essentially
wrapped-up or direct OS API calls and can be called at any time from any
thread, without any extra protection, and operate correctly,
(correctly according to SDK/MSDN, not necessarily correctly for your app
<g>).

Rgds,
Martin

0 new messages