Delphi 队列和同步

oalqel3c  于 2022-11-23  发布在  其他
关注(0)|答案(1)|浏览(255)

我在网上阅读Nick Hodges的文章,我发现了队列,但它的行为并不像我预期的那样,我不明白他和文档说了什么。看下面的代码:

TThread.CreateAnonymousThread(
  procedure
   begin

     TThread.Queue(TThread.Current, procedure
                                          begin
                                           Memo1.Lines.Clear;
                                           Memo1.Lines.Add('start');
                                          end);

     Sleep(2000);

     TThread.Synchronize(TThread.Current, procedure
                                          begin
                                           Memo1.Lines.Add('end');
                                          end);

   end
 ).Start;

我一直使用Synchronize,但这次我尝试使用Queue,因为根据Nick的说法,在多个请求的情况下使用Queue更好,因为它们不会被“序列化”并一个接一个地执行。上面的代码工作正常。为什么这不工作呢?

TThread.CreateAnonymousThread(
  procedure
   begin

     TThread.Queue(TThread.Current, procedure
                                          begin
                                           Memo1.Lines.Clear;
                                           Memo1.Lines.Add('start');
                                          end);

     Sleep(2000);

     TThread.Queue(TThread.Current, procedure
                                          begin
                                           Memo1.Lines.Add('end');
                                          end);

   end
 ).Start;

在这种情况下,Memo输出start,但不输出结尾。当我调用:

  • 第一次同步和第二次同步有效
  • 第一次排队,第二次同步,它起作用
  • 两次排队都不起作用,因为我在备忘录中只看到start
svdrlsy4

svdrlsy41#

queue和synchronize的区别在于Synchronize()将调用放入队列并等待该调用完成,而Queue()将调用放入队列并直接将控制返回给线程。
但是......这在官方文档中没有提到,当线程完成时,所有放在Queue(AThread, AMethod)队列中的调用都会被删除,其中AThread是自己的线程。
你可以在TThread.Destroy()的源代码中清楚地看到这一点,其中调用了RemoveQueuedEvents(Self)
RemoveQueuedEvents删除排队的方法调用。[...]如果指定了AThread,则删除此线程排队的所有方法调用。
因此,在您的最后一个Queue()之后,您的线程立即结束,TThread.Destroy()被执行,并且最后一个调用被从队列中删除。
你可以做一些事情来解决这个问题。

  • 就像注解中提到的,你可以调用TThread.Queue(nil, AMethod)。B.T.W.调用TThread.Queue(AMethod)TThread.Queue(Self, AMethod)是一样的,所以如果线程要结束,你需要使用nil变量。
  • 但是......如果在执行调用时仍需要激活线程(对于来自它的一些数据),您需要阻止线程退出。您可以通过使用Synchronize()作为最后一个queue-method来实现这一点。请注意,最后一个synchronize不必是一个真实的的过程。您可以只在TThread.Execute的末尾调用synchronize到一个伪过程,如Synchronize(DummySync)example)。队列是FIFO,因此线程将等待,直到队列中的所有调用都被处理(包括空的dummysync)。

在这些页面上可以找到一些额外的信息
Ensure all TThread.Queue methods complete before thread self-destructs
http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/

相关问题