我在网上阅读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
1条答案
按热度按时间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/