Delphi队列和同步

时间:2017-02-16 17:31:33

标签: multithreading delphi

我在线阅读Nick Hodges并且我发现了Queue,但它并没有像我预期的那样表现,我无法理解他和文档所说的内容。看看这段代码:

 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的说法,如果有多个请求,那就更好了,因为他们不会被"序列化&#34 ;并逐一执行。上面的代码工作正常。为什么这不起作用?

 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;

在这种情况下,备忘录输出start但不输出结尾。我打电话的时候:

  • 同步第一个,同步第二个<​​/ li>
  • 在第一个队列上排队,在第二个队列上同步
  • 因为我只看到备忘录中的start
  • ,因此两次排队都不起作用

1 个答案:

答案 0 :(得分:18)

队列和同步之间的区别在于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-variant。
  • 但是......如果你在执行调用时仍然需要线程激活(对于某些数据),你需要阻止线程退出。您可以使用Synchronize()作为最后一个队列方法来实现。请注意,最后一次同步不必是真正的过程。您可以在TThread.Execute 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/