【问题标题】:Can I move Delphi TThread.Synchronize() locally to a VCL form to be called from both a main or worker thread?我可以将 Delphi TThread.Synchronize() 本地移动到 VCL 表单以从主线程或工作线程调用吗?
【发布时间】:2015-07-07 06:57:21
【问题描述】:

我将 CreateAnonymousThread 用于工作任务,当我开始使用它时,我根据文档示例在整个声明中使用了 Synchronize,例如:

procedure Txxx.RunWorker;
begin
     FExecutionThread := TThread.CreateAnonymousThread(procedure ()
     begin

        TThread.Synchronize (TThread.CurrentThread,
          procedure ()
          begin
            // Here before worker stuff
            NotifyBeforeWorkerStuff; 

          end);

        // Do worker stuff

        TThread.Synchronize (TThread.CurrentThread,
          procedure ()
          begin
            // Here after worker stuff
            NotifyAfterWorkerStuff;
          end);
      end);

      FExecutionThread.Start;
    end;
end;

如您所见,在此线程中,我向应用程序的各个部分启动事件通知,包括 VCL 表单(NotifyBeforeWorkerStuff 等)。 后来,我发现我可以将 Synchronize() 更本地地移动到每个 VCL 表单,靠近实际需要它来更新(非安全)VCL 控件的点:

    procedure TSomeVCLForm.ReceiveNotification;
    begin
      TThread.Synchronize (TThread.CurrentThread,
          procedure ()
          begin
            Label1.Caption := GetSomeStringFunction;
          end);
     end;

只要我接受来自主线程或工作线程的通知,工作线程就会变得更简单:

   procedure Txxx.RunWorker;
   begin
     FExecutionThread := TThread.CreateAnonymousThread(procedure ()
       begin

         NotifyBeforeWorkerStuff; 

         // Do worker stuff

         NotifyAfterWorkerStuff;

       end);

     FExecutionThread.Start;
   end;

我有几个关于这是否正确的问题:

  1. 我的通知可能来自工作线程,也可能来自主线程(例如,来自按钮按下)。那么,当从主线程调用 VCL 表单上的 'ReceiveNotification' 时,是否允许像上面那样调用 TThread.Synchronize? the XE8 docs 暗示不是,但检查 System.Classes 这看起来没问题,并且工作正常。
  2. 在 Label1.Caption 从 GetSomeStringFunction 获取字符串时的“ReceiveNotification”内,即使调用来自工作线程,也绝对不需要在该函数内锁定是否正确?

感谢您的建议。

【问题讨论】:

    标签: multithreading delphi thread-safety anonymous-methods


    【解决方案1】:

    文档说:

    警告:不要在主线程中调用 Synchronize。这可能会导致无限循环。

    我认为文档完全是错误的。 XE8 中的实现检查当前线程是否是主线程。如果是,则直接执行该方法。

    ReceiveNotification 中不需要锁定,因为对GetSomeStringFunction 的调用始终在主线程上执行。

    【讨论】:

    • 谢谢大卫,正如我所愿!
    • 仅供参考,您不需要使用TThread.CurrentThread,您可以指定nil
    • @BrianFrost:是的。我想该参数只是为了帮助编译器区分class 和非class 版本。如果参数不是nil,则class 版本只需调用TThread 对象上的非class 版本,否则直接进入同一个队列。所以指定nil 总是安全的,它避免了不必要的CALL 指令。
    • @RemyLebeau,在评论Passing value to synchronize thread 中,您说从主线程调用Synchronize 到也调用自身Synchronize 的过程将导致无限递归循环.这意味着文档是正确的,但信息量可能不够。
    • @LURD 任何调用自身的方法都可能导致无限递归循环。这与Synchronize() 无关。
    猜你喜欢
    • 2015-04-03
    • 2013-03-09
    • 1970-01-01
    • 2016-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多