Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何按需启动/停止监视Delphi线程?_Multithreading_Delphi_Ondemand - Fatal编程技术网

Multithreading 如何按需启动/停止监视Delphi线程?

Multithreading 如何按需启动/停止监视Delphi线程?,multithreading,delphi,ondemand,Multithreading,Delphi,Ondemand,我一直在寻找一种在Delphi中监视特定注册表更改的方法。在about.com上找到一个: procedure TRegMonitorThread.Execute; begin InitThread; // method omitted here while not Terminated do begin if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then begin fChangeD

我一直在寻找一种在Delphi中监视特定注册表更改的方法。在about.com上找到一个:

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;
在我的应用程序中,我需要根据需要启动和停止这个线程,但上面的代码不允许这样做。仅仅设置终止标志是不行的


以某种方式告诉线程停止等待,然后释放它并在需要时创建一个新线程就足够了。如何更改此代码以实现此目的?

相反,在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方法可以用来临时停止线程,但Delphi2010现在承认它们不安全。请参见和

相反,在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方法可以用来临时停止线程,但Delphi2010现在承认它们不安全。请参见并使用
WaitForMultipleObjects()
和两个事件的数组,而不是
WaitForSingleObject()
。将手动重置事件添加到线程类,并在将
终止
设置为
后发出信号。检查两个事件中哪一个已发出信号的返回值,并相应地采取行动

编辑:

一些Delphi2009代码演示了这个想法。您必须将
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;
构造函数TTesthread.Create;
开始
继承创建(TRUE);
fTerminateEvent:=TEvent.Create(nil,True,False,”);
// ...
简历
结束;
析构函数TTesthread.Destroy;
开始
fTerminateEvent.SetEvent;
终止;//如果您没有在代码中检查终止,则不需要
等待;
fTerminateEvent.Free;
继承;
结束;
程序TTesthread.Execute;
变量
句柄:THandle的数组[0..1];
开始
句柄[0]:=…;//您的事件句柄位于此处
句柄[1]:=fTerminateEvent.Handle;
虽然没有终止,但不要开始
如果WaitForMultipleObjects(2,@Handles[0],False,无限)等待\u OBJECT\u 0,则
打破
// ...
结束;
结束;

您只需将问题中的代码添加到其中。只要尝试释放线程实例,就会执行解除阻止线程所需的所有操作(如果需要)。

使用带有两个事件数组的
WaitForSingleObject()
,而不是
WaitForSingleObject()
。将手动重置事件添加到线程类,并在将
终止
设置为
后发出信号。检查两个事件中哪一个已发出信号的返回值,并相应地采取行动

编辑:

一些Delphi2009代码演示了这个想法。您必须将
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;
构造函数TTesthread.Create;
开始
继承创建(TRUE);
fTerminateEvent:=TEvent.Create(nil,True,False,”);
// ...
简历
结束;
析构函数TTesthread.Destroy;
开始
fTerminateEvent.SetEvent;
终止;//如果您没有在代码中检查终止,则不需要
等待;
fTerminateEvent.Free;
继承;
结束;
程序TTesthread.Execute;
变量
句柄:THandle的数组[0..1];
开始
句柄[0]:=…;//您的事件句柄位于此处
句柄[1]:=fTerminateEvent.Handle;
虽然没有终止,但不要开始
如果WaitForMultipleObjects(2,@Handles[0],False,无限)等待\u OBJECT\u 0,则
打破
// ...
结束;
结束;

您只需将问题中的代码添加到其中。只要尝试释放线程实例,就可以执行解除阻止线程所需的所有操作(如果需要)。

这可以正常工作,只需进行如下小更改,现在调用Terminate时即可:

  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;
tregmonitorhread=class(TThread)
...
公众的
程序终止;重新引入;
...
程序Tregmonitorhread。终止;//增加新的公共程序
开始
继承终止;
SetEvent(FEvent);
结束;
程序tregmonitorhread.Execute;
开始
初始化线程;
虽然没有终止
开始
如果WaitForSingleObject(FEvent,INFINITE)=WAIT_OBJECT_0,则
开始

如果终止,则//此操作有效,只需进行如下小更改,现在当您调用Terminate时:

  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;
tregmonitorhread=class(TThread)
...
公众的
程序终止;重新引入;
...
程序Tregmonitorhread。终止;//增加新的公共程序
开始
继承终止;
SetEvent(FEvent);
结束;
程序tregmonitorhread.Execute;
开始
初始化线程;
虽然没有终止
开始
如果WaitForSingleObject(FEvent,INFINITE)=WAIT_OBJECT_0,则
开始

如果终止,那么//我就是这么做的,只是我甚至不用使用
Terminated
。该属性不是线程友好的机制。我以独占方式使用终止事件,然后简单地为其他线程提供一个新方法,以便它们在想要停止线程时调用。这是我的首选方法,但我如何创建该自定义事件,以及如何将其发送到没有窗口句柄的线程以接收消息?(我不太了解各种(Msg)WaitForXXX API以及它们在Delphi中应该如何使用。这些API表面上是在等待“对象”,但没有Delphi意义上的对象,而且“事件”在Delphi中似乎也不是什么意思。对我来说,这是一个非常令人困惑的领域。)@Rob:Setting
Terminated
确实没有必要,但我还是会这样做,以防有线程代码检查它。否则线程关闭将花费比严格必要的时间更长的时间。谢谢,mghie!这似乎涵盖了一切。我不太清楚的最后一件事是如何知道这两者中的哪一个