【问题标题】:Delphi. How to know if TEvent is Signaled or not?德尔福。如何知道 TEvent 是否已发出信号?
【发布时间】:2011-06-06 09:17:56
【问题描述】:

请告诉我:如何知道 TEvent 是否已发出信号?

点击停止按钮 = SetEvent(Events[1]);

我正在尝试解压缩档案,如果按下 STOP 按钮,则必须终止踏板并且必须中止解压缩。

我的代码:

procedure TForm2.ZipForge1OverallProgress(Sender: TObject; Progress: Double;
  Operation: TZFProcessOperation; ProgressPhase: TZFProgressPhase;
  var Cancel: Boolean);
begin
  if Events[1]<>null then
  begin
    ThreadUpdating.Terminate;
    Abort;
  end else
    form2.Update_ProgressBar.Position := Trunc(Progress);
end;

但是如果我按下 STOP-button(SetEvent(Events[1])) 什么都不会发生。

PS:我在一个线程中使用WaitForMultipleObjects(Event[1],Event[2])。事件 [1] 分两部分用作 STOP 信号:ZipForge1OverallProgressWaitForMultipleObjects

【问题讨论】:

    标签: delphi events signals terminate


    【解决方案1】:

    请致电WaitForMultipleObjects,但要正确操作。您还没有显示该代码,而且您显示的代码看起来也不正确。

    首先,您似乎正在尝试检查 Events[1] 元素是否为空指针。 Delphi 中的空指针拼写为nil,而不是null;后者是a function that returns a null Variant value(但由于Variant 可以转换为许多其他类型,编译器可能不会提醒您代码错误)。接下来,您正在处理的事件看起来好像有一个 Cancel 参数,您可以设置该参数以通知调用者它应该停止正在执行的操作,但不是仅仅设置它,而是抛出一个 EAbort 异常.

    如果您在此处显示的进度事件确实在单独的线程中运行,则它不得修改 VCL 对象的属性,例如TProgressBar。您需要使用Synchronize 来确保VCL 操作只发生在VCL 线程中。

    正如我所说,您需要调用WaitForMultipleObjects 属性。这意味着向它传递四个参数,一方面。您似乎有一个数组,其中至少有两个句柄,所以这样称呼它:

    var
      Ret: DWord;
    
    Ret := WaitForMultipleObjects(2, @Events[1], False, Timeout);
    case Ret of
      Wait_Object_0: begin
        // Events[1] is signaled
      end;
      Wait_Object_0 + 1: begin
        // Events[2] is signaled
      end;
      Wait_Timeout: begin
        // Neither is signaled. Do some more work, or go back to waiting.
      end;
      Wait_Failed: begin
        RaiseLastOSError;
      end;
    end;
    

    如果您只想检查句柄是否已发出信号,但您不想等待如果它尚未发出信号,然后使用零超时值。

    【讨论】:

    • 好点,我假设处理程序是从同步方法调用的,但可能不是......
    • 我的代码。一开始:form2.ZipForge1.ExtractFiles('.'); ... 然后 ObjectSignal:=WaitForMultipleObjects(2, @Events,false, INFINITE);如果 ObjectSignal=WAIT_OBJECT_0 那么...;事件 #2 设置了一些东西,我们不在乎。事件 #1(停止按钮):如果在解压缩 WaitForMultipleObjects 后按下停止按钮 (SetEvent#1) 将做出反应。但是如果我在解压缩时按下停止按钮? ZipForge 必须知道我按下了按钮,必须中止并且必须完成 Thread.Terminate。如果我使用布尔值而不是事件来检查它,他们很难过,那么布尔值可能是错误的,价值可以是现金,所以我使用 TEvent。
    • “他们”是在谈论使用布尔值来检查是否已按下“停止”按钮,而不是使用布尔值来停止对 zip 文件的进一步处理。 “他们”明确给了一个布尔变量供您填写(Cancel 参数)。您应该像文档肯定告诉您的那样修改它。你不需要抛出异常。并且不要无限地等待事件发出信号——这会适得其反,因为您会阻止 zip 文件被进一步处理。
    • @RobKennedy,我尝试了很多次试图理解WaitForMultipleObjects,但直到我阅读了你上面提供的这个代码示例,我才理解它。谢谢!
    【解决方案2】:

    'if Events[1]null then begin' 这是伪代码吗?不喜欢 - 在我看来更像是真正的 Delphi :) 如果是这样,您只是在检查 Event 对象是否已分配,而不是发出信号。

    如果您想在您的OverallProgress 处理程序中轮询停止事件,您需要调用WaitForSingleObject(),超时时间为0。

    您不能只检查处理程序中的“停止”布尔值吗?这将比内核调用快得多。您可能还需要该事件,以便在需要中止/终止时向线程顶部的 WFMO 调用发出信号,或者您可以通过始终检查停止来发送信号 WFMO 数组中的其他事件:

    TmyThread = class(TThread)
    ..
    public
      stopRequested:boolean;
      procedure stop;
      ..
    end;
    
    procedure TmyThread.stop;
    begin
      stopRequested:=true;
      someEventInWFMOarray.signal;
    end;
    
    procedure TmyThread.execute;
    begin;
      while true do
      begin
        waitForMultipeObjects();
        if stopRequested then exit;
        work;
      end;
    end;
    
    TForm2.ZipForge1OverallProgress(sender:TObject,......)
    begin
      cancel:=TmyThread(Sender).stopRequested;
      if cancel then exit;
      doStuff; 
    end;
    

    【讨论】:

    • 我的代码。一开始:form2.ZipForge1.ExtractFiles('.'); ... 然后 ObjectSignal:=WaitForMultipleObjects(2, @Events,false, INFINITE);如果 ObjectSignal=WAIT_OBJECT_0 那么...;事件 #2 设置了一些东西,我们不在乎。事件 #1(停止按钮):如果在解压缩 WaitForMultipleObjects 后按下停止按钮 (SetEvent#1) 将做出反应。但是如果我在解压缩时按下停止按钮? ZipForge 必须知道我按下了按钮,必须中止并且必须完成 Thread.Terminate。如果我使用布尔值而不是事件来检查它,他们很难过,那么布尔值可能是错误的,价值可以是现金,所以我使用 TEvent。
    • @Michael:如果您想提供更多信息(例如添加一些代码示例),您可以编辑您的问题。在 cmets 中,您可以通过用反引号 ( ` ) 字符将代码括起来来使代码更具可读性。
    猜你喜欢
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    相关资源
    最近更新 更多