Articles   Members Online: 3
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
How to create user-defined messages in a TThread Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
30-Aug-02
Category
Win API
Language
Delphi 2.x
Views
84
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			 Author: Tomas Rutkauskas

I try to build a thread that I can send a message to order to stop. I know that 
messages are normally used for screen object but the thread is also having a 
handle. I 'd like to be able to send a message to this thread and having the sender 
waiting until the stop is confirmed. (or something that's equivalent)

Answer:

A thread has a handle, but it is not a window handle, so you cannot send a message 
to it with SendMessage. There is a PostThreadMessage API function that can be used 
to send a message to the thread itself. But to receive it the thread needs a 
message loop, which threads normally don't have.

If your thread is permanently slaving away in a work loop and you want to stop it 
just set a boolean field declared in the thread object to true (this is what 
Thread.Terminate does, for example). The work code inside the thread has to check 
this field regularly to detect that it has been set, and then exit the loop.

If the thread is waiting on something and you want to wake it up you have to modify 
the wait code so that it uses WaitforMultipleObjects, one of which is an event 
object you can signal from outside to wake the thread up.

Here is an example for this technique:

1   {Writing an interruptible timer thread}
2   
3   unit Unit1;
4   
5   interface
6   
7   uses
8     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
9   ComCtrls, StdCtrls;
10  
11  type
12    TTimerThread = class;
13    TWakeupKind = (wkTimerExpired, wkEventTriggered);
14    TWaitState = (wsIdle, wsWaiting);
15    TWakeupEvent = procedure(sender: TTimerThread; reason: TWakeupKind) of object;
16    TTimerThread = class(TThread)
17    private
18      FInterval: DWORD;
19      FReason: TWakeupKind;
20      FEvent: THandle;
21      FState: TwaitState;
22      FWakeupEvent: TWakeupEvent;
23      FNoWakeupEvent: Boolean;
24      procedure SyncWakeup;
25    protected
26      procedure DoWakeup;
27    public
28      constructor Create; reintroduce;
29      destructor Destroy; override;
30      procedure Execute; override;
31      procedure Sleep(forInterval: DWORD);
32      procedure Wakeup;
33      procedure Terminate;
34      property OnWakeup: TWakeupEvent read FWakeupEvent write FWakeupEvent;
35      property Interval: DWORD read FInterval write FInterval;
36      property State: TWaitState read FState;
37    end; {TTimerThread}
38  
39    TForm1 = class(TForm)
40      StatusBar: TStatusBar;
41      WaitButton: TButton;
42      OpenDialog1: TOpenDialog;
43      Label1: TLabel;
44      WaitIntervalEdit: TEdit;
45      WakeupButton: TButton;
46      Memo1: TMemo;
47      procedure WaitIntervalEditKeyPress(Sender: TObject; var Key: Char);
48      procedure WaitButtonClick(Sender: TObject);
49      procedure FormCreate(Sender: TObject);
50      procedure FormDestroy(Sender: TObject);
51      procedure WakeupButtonClick(Sender: TObject);
52    private
53      { Private declarations }
54      FTimerthread: TTimerThread;
55      procedure TimerWakeup(sender: TTimerThread; reason: TWakeupKind);
56    public
57      { Public declarations }
58    end;
59  
60  var
61    Form1: TForm1;
62  
63  implementation
64  
65  uses typinfo;
66  
67  {$R *.DFM}
68  
69  procedure TForm1.WaitIntervalEditKeyPress(Sender: TObject; var Key: Char);
70  begin
71    if not (key in ['0'..'9', #8]) then
72      Key := #0;
73  end;
74  
75  procedure TForm1.WaitButtonClick(Sender: TObject);
76  begin
77    FTimerThread.Sleep(StrToInt(WaitIntervalEdit.Text));
78    memo1.lines.add('Timer started');
79  end;
80  
81  procedure TForm1.FormCreate(Sender: TObject);
82  begin
83    FTimerthread := TTimerThread.Create;
84    FTimerthread.FreeOnTerminate := true;
85    FTimerthread.OnWakeup := TimerWakeup;
86  end;
87  
88  procedure TForm1.TimerWakeup(sender: TTimerThread; reason: TWakeupKind);
89  begin
90    memo1.lines.add('Timer woke up, reason: ' + GetEnumName(Typeinfo(TWakeupKind),
91      Ord(reason)));
92  end;
93  
94  procedure TForm1.FormDestroy(Sender: TObject);
95  begin
96    if Assigned(FTimerthread) then
97      FTimerThread.Terminate;
98  end;
99  
100 procedure TForm1.WakeupButtonClick(Sender: TObject);
101 begin
102   FTimerthread.Wakeup;
103 end;
104 
105 { TTimerThread }
106 
107 constructor TTimerThread.Create;
108 begin
109   {create thread suspended}
110   inherited Create(true);
111   {create event object}
112   FEvent := CreateEvent(
113     nil, {use default security}
114     true, {event will be manually reset}
115     false, {event starts out not signaled}
116     nil); {event has no name}
117   if FEvent = 0 then
118     raise Exception.CreateFmt('TTimerThread.Create: could not create API event
119       handle. 'Syserrormessage( GetLastError ) ] );
120       {thread will stay suspended until started by a Sleep or Resume call}
121       FState := wsIdle;
122       FNoWakeupEvent := False;
123 end;
124 
125 destructor TTimerThread.Destroy;
126 begin
127   inherited;
128   if FEvent <> 0 then
129     CloseHandle(FEvent);
130 end;
131 
132 procedure TTimerThread.DoWakeup;
133 begin
134   {called in threads context to fire OnWakeup event}
135   if Assigned(FWakeupEvent) and not FNoWakeupEvent then
136     Synchronize(SyncWakeup);
137 end;
138 
139 procedure TTimerThread.Execute;
140 var
141   res: DWORD;
142 begin
143   {Executes inside threads context}
144   repeat
145     Fstate := wsWaiting;
146     res := WaitForSingleObject(FEvent, FInterval);
147     if res = WAIT_OBJECT_0 then
148     begin
149       FReason := wkEventTriggered;
150       ResetEvent(FEvent);
151     end
152     else
153       FReason := wkTimerExpired;
154     DoWakeup;
155     if not Terminated then
156     begin
157       Fstate := wsIdle;
158       Suspend;
159     end;
160   until
161     Terminated;
162 end;
163 
164 procedure TTimerThread.Sleep(forInterval: DWORD);
165 begin
166   {called from outside threads context to start thread sleeping}
167   Interval := forInterval;
168   if State <> wsIdle then
169   begin
170     {thread is already waiting. Wake it up but disable wakeup event}
171     FNoWakeupEvent := true;
172     try
173       Wakeup;
174       while State = wsWaiting do
175         Windows.Sleep(10);
176     finally
177       FNoWakeupEvent := false;
178     end;
179   end;
180   Resume;
181 end;
182 
183 procedure TTimerThread.SyncWakeup;
184 begin
185   {executes in main threads context}
186   {Note: FWakeupevent has already been checked to be <> nil in DoWakeup}
187   FWakeupEvent(self, FReason);
188 end;
189 
190 procedure TTimerThread.Terminate;
191 begin
192   inherited Terminate;
193   {in case thread is waiting, don't fire Wakeup event on wakeup}
194   FNoWakeupEvent := true;
195   Wakeup;
196 end;
197 
198 procedure TTimerThread.Wakeup;
199 begin
200   {executes in callers thread context}
201   if State = wsWaiting then
202     SetEvent(FEvent);
203 end;
204 
205 end.


			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC