Board index » cppbuilder » about tthread: how to make threads run loop ?

about tthread: how to make threads run loop ?


2004-12-02 12:41:43 AM
cppbuilder45
hi,
my question is "how to make threads run loop" , ie., when use objects
instanced from TThread based classes, I need the threads run nonstop and
one by one, for instance, as detailed in below:
thread1: put a number to Memo1, and inform thread2 that it is done and
then wait for the signal that thread3 set, if the signal is set, thread1
put a new number to the Memo1, this is a loop circle.
thread2: as informed by thread1, try to get the number that thread1 just
put to the Memo1, then add a number to the number it just got the put the
new number to Memo2, then inform thread3 that it is done, then wait for
the msg from thread1, if the msg(ie., the signal is set by thread1), it
will try to get the number newly put to Memo1 by thread1, this is another
loop.
thread3: as informed by thread2, thread3 try to get the number in Memo2,
add a new number to it and put the result to Memo3, and set a signal to
inform thread1, then wait for another signal set by thread2.
I just want some code to learn how to treat with this situation, as you
can see, for the description shown as above, multi-thread tec is not
useful here, I just want to learn the way to treat with this situation.
If my description is clear enough, pls teach me how to solve the problem.
thanks alot.
frank
 
 

Re:about tthread: how to make threads run loop ?

"frank" < XXXX@XXXXX.COM >wrote in message
Quote
my question is "how to make threads run loop" , ie., when use
objects instanced from TThread based classes, I need the threads
run nonstop and one by one, for instance, as detailed in below:
That is quite a complex design. Why exactly are you using three threads to
do the work that a single thread can accomplish instead?
If you must use multiple threads, then look at CreateEvent(), SetEvent(),
and WaitForSingleObject() from the Win32 API. For example:
class TThread1 : public TThread
{
private:
HANDLE hThread1Event;
HANDLE hThread2Event;
void __fastcall AddNumberToMemo();
void __fastcall WaitForSignal();
protected:
void __fastcall Execute();
public:
__fastcall TThread1();
__fastcall ~TThread1();
};
__fastcall TThread1::TThread1()
: TThread(true)
{
hThread1Event = CreateEvent(NULL, FALSE, FALSE, "Thread1Event");
hThread2Event = CreateEvent(NULL, FALSE, FALSE, "Thread2Event");
Resume();
}
__fastcall TThread1::~TThread1()
{
CloseHandle(hThread1Event);
CloseHandle(hThread2Event);
}
void __fastcall TThread1::Execute()
{
while( !Terminated )
{
Synchronize(AddNumberToMemo);
SetEvent(hThread2Event);
if( !WaitForSignal() )
break;
}
}
void __fastcall TThread1::WaitForSignal()
{
DWORD dwWaitResult;
do
{
dwWaitResult = WaitForSingleObject(hThread1Event, 1000);
if( dwWaitResult != WAIT_TIMEOUT )
break;
}
while( !Terminated );
return ( dwWaitResult == WAIT_OBJECT_0 );
}
void __fastcall TThread1::AddNumberToMemo()
{
Form1->Memo1->Lines->Add(SomeNumber);
}
class TThread2 : public TThread
{
private:
HANDLE hThread2Event;
HANDLE hThread3Event;
int FNumber;
void __fastcall GetNumberFromMemo();
void __fastcall AddNumberToMemo();
void __fastcall WaitForSignal();
protected:
void __fastcall Execute();
public:
__fastcall TThread2();
__fastcall ~TThread2();
};
__fastcall TThread2::TThread2()
: TThread(true)
{
hThread2Event = CreateEvent(NULL, FALSE, FALSE, "Thread2Event");
hThread3Event = CreateEvent(NULL, FALSE, FALSE, "Thread3Event");
Resume();
}
__fastcall TThread2::~TThread2()
{
CloseHandle(hThread2Event);
CloseHandle(hThread3Event);
}
void __fastcall TThread2::Execute()
{
while( !Terminated )
{
if( !WaitForSignal() )
break;
Synchronize(GetNumberFromMemo);
FNumber += SomeOtherValue;
Synchronize(AddNumberToMemo);
SetEvent(hThread3Event);
}
}
void __fastcall TThread1::WaitForSignal()
{
DWORD dwWaitResult;
do
{
dwWaitResult = WaitForSingleObject(hThread2Event, 1000);
if( dwWaitResult != WAIT_TIMEOUT )
break;
}
while( !Terminated );
return (dwWaitResult == WAIT_OBJECT_0);
}
void __fastcall TThread2::GetNumberFromMemo()
{
int count = Form1->Memo1->Lines->Count;
if( count>0 )
FNumber = Form1->Memo1->Lines->Strings[count-1].ToInt();
else
FNumber = 0;
}
void __fastcall TThread2::AddNumberToMemo()
{
Form1->Memo2->Lines->Add(FNumber);
}
class TThread3 : public TThread
{
private:
HANDLE hThread1Event;
HANDLE hThread3Event;
int FNumber;
void __fastcall GetNumberFromMemo();
void __fastcall AddNumberToMemo();
void __fastcall WaitForSignal();
protected:
void __fastcall Execute();
public:
__fastcall TThread3();
__fastcall ~TThread3();
};
__fastcall TThread3::TThread3()
: TThread(true)
{
hThread1Event = CreateEvent(NULL, FALSE, FALSE, "Thread1Event");
hThread2Event = CreateEvent(NULL, FALSE, FALSE, "Thread3Event");
Resume();
}
__fastcall TThread3::~TThread3()
{
CloseHandle(hThread1Event);
CloseHandle(hThread3Event);
}
void __fastcall TThread3::Execute()
{
while( !Terminated )
{
if( !WaitForSignal() )
break;
Synchronize(GetNumberFromMemo);
FNumber += SomeOtherValue;
Synchronize(AddNumberToMemo);
SetEvent(hThread1Event);
}
}
void __fastcall TThread3::WaitForSignal()
{
DWORD dwWaitResult;
do
{
dwWaitResult = WaitForSingleObject(hThread3Event, 1000);
if( dwWaitResult != WAIT_TIMEOUT )
break;
}
while( !Terminated );
return (dwWaitResult == WAIT_OBJECT_0);
}
void __fastcall TThread3::GetNumberFromMemo()
{
int count = Form1->Memo2->Lines->Count;
if( count>0 )
FNumber = Form1->Memo2->Lines->Strings[count-1].ToInt();
else
FNumber = 0;
}
void __fastcall TThread3::AddNumberToMemo()
{
Form1->Memo3->Lines->Add(FNumber);
}
Gambit
 

Re:about tthread: how to make threads run loop ?

Many thanks to Gambit.
2 more questions about the reply:
1) If I insist on TEvent rather than Win32's API, what can I do ?
2) There is hard code lines in the reply which let me wait for 1
second,as below:
dwWaitResult = WaitForSingleObject(hThread3Event, 1000);
I hope the waiting is smart, as soon as the hThread3Event set, it
returns a signal, if it is time out(ie.,1000 second or some other time
span elapsed). Does the line above fit it?
Thanks again !!!!
At Wed, 1 Dec 2004 10:23:01 -0800,Remy Lebeau (TeamB)
< XXXX@XXXXX.COM >wrote:
Quote
That is quite a complex design. Why exactly are you using three threads
to
do the work that a single thread can accomplish instead?

If you must use multiple threads, then look at CreateEvent(), SetEvent(),
and WaitForSingleObject() from the Win32 API. For example:

class TThread1 : public TThread
.......
Gambit


--
 

{smallsort}

Re:about tthread: how to make threads run loop ?

"frank" < XXXX@XXXXX.COM >wrote in message
Quote
1) If I insist on TEvent rather than Win32's API, what can I do ?
It doesn't really matter which way you go. You end up using the same logic
either way. TEvent internally uses the exact same API functions that I
mentioned earlier. So why invoke the extra overhead that TEvent brings to
do the same thing as with using the API directly? If you must use TEvent,
though, then it would be like the following:
class TThread1 : public TThread
{
private:
TEvent *Thread1Event;
TEvent *Thread2Event;
void __fastcall AddNumberToMemo();
void __fastcall WaitForSignal();
protected:
void __fastcall Execute();
public:
__fastcall TThread1();
__fastcall ~TThread1();
};
__fastcall TThread1::TThread1()
: TThread(true)
{
Thread1Event = new TEvent(NULL, false, false, "Thread1Event");
Thread2Event = new TEvent(NULL, false, false, "Thread2Event");
Resume();
}
__fastcall TThread1::~TThread1()
{
delete Thread1Event;
delete Thread2Event;
}
void __fastcall TThread1::Execute()
{
while( !Terminated )
{
Synchronize(AddNumberToMemo);
Thread2Event->SetEvent();
if( !WaitForSignal() )
break;
}
}
void __fastcall TThread1::WaitForSignal()
{
TWaitResult WaitResult;
do
{
WaitResult = Thread1Event->WaitFor(1000);
if( WaitResult != wrTimeout )
break;
}
while( !Terminated );
return ( WaitResult == wrSignaled );
}
void __fastcall TThread1::AddNumberToMemo()
{
Form1->Memo1->Lines->Add(SomeNumber);
}
class TThread2 : public TThread
{
private:
TEvent *Thread2Event;
TEvent *Thread3Event;
int FNumber;
void __fastcall GetNumberFromMemo();
void __fastcall AddNumberToMemo();
void __fastcall WaitForSignal();
protected:
void __fastcall Execute();
public:
__fastcall TThread2();
__fastcall ~TThread2();
};
__fastcall TThread2::TThread2()
: TThread(true)
{
Thread2Event = new TEvent(NULL, false, false, "Thread2Event");
Thread3Event = new TEvent(NULL, false, false, "Thread3Event");
Resume();
}
__fastcall TThread2::~TThread2()
{
delete Thread2Event;
delete Thread3Event;
}
void __fastcall TThread2::Execute()
{
while( !Terminated )
{
if( !WaitForSignal() )
break;
Synchronize(GetNumberFromMemo);
FNumber += SomeOtherValue;
Synchronize(AddNumberToMemo);
Thread3Event->SetEvent();
}
}
void __fastcall TThread1::WaitForSignal()
{
TWaitResult WaitResult;
do
{
WaitResult = Thread2Event->WaitFor(1000);
if( WaitResult != wrTimeout )
break;
}
while( !Terminated );
return ( WaitResult == wrSignaled );
}
void __fastcall TThread2::GetNumberFromMemo()
{
int count = Form1->Memo1->Lines->Count;
if( count>0 )
FNumber = Form1->Memo1->Lines->Strings[count-1].ToInt();
else
FNumber = 0;
}
void __fastcall TThread2::AddNumberToMemo()
{
Form1->Memo2->Lines->Add(FNumber);
}
class TThread3 : public TThread
{
private:
TEvent *Thread1Event;
TEvent *Thread3Event;
int FNumber;
void __fastcall GetNumberFromMemo();
void __fastcall AddNumberToMemo();
void __fastcall WaitForSignal();
protected:
void __fastcall Execute();
public:
__fastcall TThread3();
__fastcall ~TThread3();
};
__fastcall TThread3::TThread3()
: TThread(true)
{
Thread1Event = new TEvent(NULL, false, false, "Thread1Event");
Thread2Event = new TEvent(NULL, false, false, "Thread3Event");
Resume();
}
__fastcall TThread3::~TThread3()
{
delete Thread1Event;
delete Thread3Event;
}
void __fastcall TThread3::Execute()
{
while( !Terminated )
{
if( !WaitForSignal() )
break;
Synchronize(GetNumberFromMemo);
FNumber += SomeOtherValue;
Synchronize(AddNumberToMemo);
Thread1Event->SetEvent();
}
}
void __fastcall TThread3::WaitForSignal()
{
TWaitResult WaitResult;
do
{
WaitResult = Thread3Event->WaitFor(1000);
if( WaitResult != wrTimeout )
break;
}
while( !Terminated );
return ( WaitResult == wrSignaled );
}
void __fastcall TThread3::GetNumberFromMemo()
{
int count = Form1->Memo2->Lines->Count;
if( count>0 )
FNumber = Form1->Memo2->Lines->Strings[count-1].ToInt();
else
FNumber = 0;
}
void __fastcall TThread3::AddNumberToMemo()
{
Form1->Memo3->Lines->Add(FNumber);
}
Quote
2) There is hard code lines in the reply which let me wait for 1
second,as below:
dwWaitResult = WaitForSingleObject(hThread3Event, 1000);
As well there should be. This allows WaitForSignal() to exit quickly when
the threads are being terminated by the Application.
Quote
I hope the waiting is smart, as soon as the hThread3Event set, it
returns a signal, if it is time out(ie.,1000 second or some other time
span elapsed). Does the line above fit it?
Yes, that is exactly what it already does. However, the reason that the
code is set up to loop is so that the thread's Terminated property can be
checked as well. WaitFor() will not do that for you, you still have to do
it yourself. You should never design threads to take forever to terminate
themselves when the application needs them to. They should terminate as
quickly as possible. That is what I am allowing the threads to do by
looping the waiting the way I showed.
Gambit
 

Re:about tthread: how to make threads run loop ?

在 Sun, 05 Dec 2004 17:21:37 +0800,frank < XXXX@XXXXX.COM >写道:
modified:
I hope the waiting is smart, as soon as the hThread3Event set, it
returns a signal, if it is time out(ie.,1000 second or some other time
span elapsed), it also returns. Does the line above fit it?
Quote
Many thanks to Gambit.
2 more questions about the reply:
1) If I insist on TEvent rather than Win32's API, what can I do ?
2) There is hard code lines in the reply which let me wait for 1
second,as below:
dwWaitResult = WaitForSingleObject(hThread3Event, 1000);
I hope the waiting is smart, as soon as the hThread3Event set, it
returns a signal, if it is time out(ie.,1000 second or some other time
span elapsed). Does the line above fit it?

Thanks again !!!!




At Wed, 1 Dec 2004 10:23:01 -0800,Remy Lebeau (TeamB)
< XXXX@XXXXX.COM >wrote:

>That is quite a complex design. Why exactly are you using three
>threads to
>do the work that a single thread can accomplish instead?
>
>If you must use multiple threads, then look at CreateEvent(),
>SetEvent(),
>and WaitForSingleObject() from the Win32 API. For example:
>
>class TThread1 : public TThread
>.......
>Gambit
>
>



--
使用 Opera 革命性的电子邮件客户程序 M2: www.opera.com/m2/
 

Re:about tthread: how to make threads run loop ?

Remy Lebeau:
after study your code, I still have a question:
* Private embers in different classes with the same name...
you put hThread1Event,hThread2Event,hThread3Event in the private section of
the classes, and in every 2 classes, there are 2 event handles in same name,
eg., Thread1 has hThread2Event, while thread2 has hThread2Event too....
I think,in the definition of the classes, the event handles are unknown to
each other, even they are in the same name.
So, in the Execute() routing of Thread1, although you set the signal of
hThread2Event, thread2's hThread2Event will not get the signal.
Meanwhile, the TEvent object is said that should be put to the global area
to be visible to all that need it.
Is this understanding right ? I am confused.
Frank
"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote:
Quote

"frank" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>1) If I insist on TEvent rather than Win32's API, what can I do ?

It doesn't really matter which way you go. You end up using the same
logic
either way. TEvent internally uses the exact same API functions that I
mentioned earlier. So why invoke the extra overhead that TEvent brings to
do the same thing as with using the API directly? If you must use TEvent,
though, then it would be like the following:
..........
Yes, that is exactly what it already does. However, the reason that the
code is set up to loop is so that the thread's Terminated property can be
checked as well. WaitFor() will not do that for you, you still have to do
it yourself. You should never design threads to take forever to terminate
themselves when the application needs them to. They should terminate as
quickly as possible. That is what I am allowing the threads to do by
looping the waiting the way I showed.


Gambit


 

Re:about tthread: how to make threads run loop ?

"Frank" < XXXX@XXXXX.COM >wrote in message
Quote
* Private embers in different classes with the same name...
Makes no difference at all. They are private. They do not interfer with
each other. They wouldn't interfer with each other even if they are public,
for that matter. They are in separate classes. They can have the same
naming.
Quote
you put hThread1Event,hThread2Event,hThread3Event in the private
section of the classes, and in every 2 classes, there are 2 event handles
in same name, eg., Thread1 has hThread2Event, while thread2 has
hThread2Event too....
That is perfectly fine.
Quote
I think,in the definition of the classes, the event handles are unknown
to each other, even they are in the same name.
Correct.
Quote
So, in the Execute() routing of Thread1, although you set the signal of
hThread2Event, thread2's hThread2Event will not get the signal.
Wrong. If you look at the thread constructors that are creating the event
instances, you will see that Thread1's hThread2Event and Thread2's
hThread2Event are both being assigned to events with the same string value.
That is intentional, it is what makes this whole design work at all. When
Thread1 signals its hThread2Event, Thread2's hThread2Event *does* get
signalled. That is how they communicate with each other - by *sharing* API
events with each other.
Quote
Meanwhile, the TEvent object is said that should be put to the
global area to be visible to all that need it.
Although that is technically correct as one way to approach the issue, I did
not go that approach with my code sample. By having the events share the
same string names with each other, there are only 3 API event objects in
memory even though there are 6 TEvent instances using them. The API event
objects are being shared amongst multiple TEvents at a time. Multiple
threads are allowed to open their own local handles to shared objects and
then signal each other back and forth via those shared objects. That is why
API objects such as events, mutexes, and semaphores have string names in the
first place. It allows them to be shared. Even across multiple processes
(ie: Thread1 in Process1 can signal an event in Thread 3 of Process3).
Quote
Is this understanding right ?
No.
Quote
I am confused.
Then I suggest you read the documentation for CreateEvent() and related
functions. There is an entire chapter in the API documentation on how
inter-thread communications work.
Gambit
 

Re:about tthread: how to make threads run loop ?

Tue, 7 Dec 2004 10:09:01 -0800,Remy Lebeau (TeamB) < XXXX@XXXXX.COM >wrote:
Thank you very much !
Remy Lebeau gave me a very good leason !
Frank
Quote

"Frank" < XXXX@XXXXX.COM >wrote in message
news:41b5d93d$ XXXX@XXXXX.COM ...

>* Private embers in different classes with the same name...

Makes no difference at all. They are private. They do not interfer with
each other. They wouldn't interfer with each other even if they are public,
for that matter. They are in separate classes. They can have the same
naming.
.............
Gambit


--
Opera M2: www.opera.com/m2/
 

Re:about tthread: how to make threads run loop ?

Still learning your code.
One question:
In Execute() , ie.,
void __fastcall TThread1::Execute()
{
while( !Terminated )
{
Synchronize(AddNumberToMemo);
Thread2Event->SetEvent();
if( !WaitForSignal() )
break;
}
}
I found the loop condition is !Terminated, which is a property of TThread
and is said to be set to true by function Termninate().
But I didnt find any lines that call Terminate() to set the property
Terminated to true.
By my poor knowledge box, I think the loop will go to unterminated dead
loop - black hole, if there is no way to set Terminated to be true and there
is no other way to go out.
The line : if( !WaitForSignal() )break; may be the only emerg exit door. But
it seems also depend on the property Terminated. After check again, I found
an emerg exit hole: the function WaitForSignal(). It is another loop depends
on the property Terminated ! Thanks the God, by the logic, there is another
thread to set the Event signal of this thread, so it has the way to survive
the black hole. The return value 'WAIT_OBJECT_0' is the key to open the life
saving exit door.
Is this understanding right ?
Further more, If I need to terminate the program, how can I set the property
Terminated of all the threads to be true ?
So, the question is : where and by what mechanism to set Terminated to true
?
Frank
"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >
wrote:41b5f1c8$ XXXX@XXXXX.COM ...
Quote

"Frank" < XXXX@XXXXX.COM >wrote in message
news:41b5d93d$ XXXX@XXXXX.COM ...

>* Private embers in different classes with the same name...

Makes no difference at all. They are private. They do not interfer with
....................

functions. There is an entire chapter in the API documentation on how
inter-thread communications work.


Gambit