我一直在寻找一种方法来监控Delphi中特定的注册表更改。在about.com找到solution:
procedure TRegMonitorThread.Execute;
begin
InitThread; // method omitted here
while not Terminated do
begin
if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then
begin
fChangeData.RootKey := RootKey;
fChangeData.Key := Key;
SendMessage(Wnd, WM_REGCHANGE, RootKey, LongInt(PChar(Key)));
ResetEvent(FEvent);
RegNotifyChangeKeyValue(FReg.CurrentKey, 1, Filter, FEvent, 1);
end;
end;
end;
在我的应用程序中,我需要按需启动和停止此线程,但上面的代码不允许这样做。只设置Terminated标志是不行的。
以某种方式告诉线程停止等待,然后释放它并在需要时创建一个新的就足够了。如何更改此代码以实现该目标?
答案 0 :(得分:8)
将WaitForMultipleObjects()
与两个事件的数组一起使用,而不是WaitForSingleObject()
。将一个手动重置事件添加到线程类,并在将Terminated
设置为True
后发出信号。检查两个事件中的哪个已发出信号的返回值,并采取相应的行动。
修改强>
一些最小的Delphi 2009代码来演示这个想法。您必须将SyncObjs
添加到已用单位列表中,然后添加
fTerminateEvent: TEvent;
到线程类的private
部分。
constructor TTestThread.Create;
begin
inherited Create(TRUE);
fTerminateEvent := TEvent.Create(nil, True, False, '');
// ...
Resume;
end;
destructor TTestThread.Destroy;
begin
fTerminateEvent.SetEvent;
Terminate; // not necessary if you don't check Terminated in your code
WaitFor;
fTerminateEvent.Free;
inherited;
end;
procedure TTestThread.Execute;
var
Handles: array[0..1] of THandle;
begin
Handles[0] := ...; // your event handle goes here
Handles[1] := fTerminateEvent.Handle;
while not Terminated do begin
if WaitForMultipleObjects(2, @Handles[0], False, INFINITE) <> WAIT_OBJECT_0 then
break;
// ...
end;
end;
您只需要在问题中添加代码即可。只需尝试释放线程实例就可以完成解锁线程所需的一切(如有必要)。
答案 1 :(得分:1)
相反,在INFINITE中,你应该在一段时间后让WaitForSingleObject超时。这样循环就会继续,并且会检查终止。
procedure TRegMonitorThread.Execute;
begin
InitThread; // method omitted here
while not Terminated do
begin
if WaitForSingleObject(FEvent, 1000) = WAIT_OBJECT_0 then
begin
fChangeData.RootKey := RootKey;
fChangeData.Key := Key;
SendMessage(Wnd, WM_REGCHANGE, RootKey, LongInt(PChar(Key)));
ResetEvent(FEvent);
RegNotifyChangeKeyValue(FReg.CurrentKey, 1, Filter, FEvent, 1);
end;
end;
end;
方法TThread.Suspend和TThread.Resume理论上可用于临时停止线程,但正如Delphi 2010现在承认它们不安全使用。请参阅TThread.resume is deprecated in Delphi-2010 what should be used in place?和http://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx
答案 2 :(得分:1)
这样做,只需进行如下的小改动,现在当你调用终止时:
TRegMonitorThread = class(TThread)
...
public
procedure Terminate; reintroduce;
...
procedure TRegMonitorThread. Terminate; // add new public procedure
begin
inherited Terminate;
Windows.SetEvent(FEvent);
end;
procedure TRegMonitorThread.Execute;
begin
InitThread;
while not Terminated do
begin
if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then
begin
if Terminated then // <- add this 2 lines
Exit;
...
end;
end;
end;