【发布时间】:2022-02-03 18:12:00
【问题描述】:
所以我创建了一个类:TWorkerThread = class(TThread)。在TWorkerThread 构造函数中,我设置了FreeOnTerminate := True。
然后我向我的TForm 添加了一个私有Worker 变量。当我为Worker 实例化TWorkerThread 时,我总是使用CreateSuspended := False。
一旦启动,我需要与线程进行的唯一交互是取消进程 (Terminate) 并检查进程是否结束(该检查基于用户事件)。
要检查线程是否仍处于活动状态,我会这样做:
if (Self.Worker <> nil) and (not Self.Worker.Finished) then
//Still active
这似乎工作正常,但我担心在某些时候TWorkerThread 将是<> nil 但仍然是.free(请记住TWorkerThread 都是FreeOnTerminate := True)。当TWorkerThread“自我毁灭”一旦终止,他们总是变成nil吗?如果没有,我该如何处理(以避免访问冲突)?
另一件事,如果Worker 在它的表单销毁上处于活动状态,我会这样做:
if (Self.Worker <> nil) and (not Self.Worker.Finished) then
begin
Self.Worker.Terminate;
//wait here for completion
end;
在Terminate 之后,如果我执行WaitFor,我会遇到访问冲突(因为自毁)。我应该在这里强制等待吗?最好的方法是什么?
这是我在 Delphi 中第一次正确使用 TThread。上面的代码是我为清楚起见所做的简化版本。
【问题讨论】:
-
一旦你在终止线程上启动了一个空闲线程,由于竞争条件,你不能调用任何方法或从线程外部引用任何字段。相反,您需要让线程在终止时通知您。
-
如果您需要检查线程状态或者您需要终止线程或任何类似的能力,您不能使用自毁线程。没有其他可行的选择。
-
@DavidHeffernan 这并不完全正确。只要 1. 线程有一个 OnTerminate 事件处理程序,并且 2. OnTerminate 事件处理程序没有对线程的引用,您仍然可以使用来自主线程的线程对象。 OnTerminate 事件总是在主线程的上下文中执行,所以只要线程引用不为 nil,就可以安全地使用线程引用。虽然需要小心调用线程的哪些函数以避免死锁。
-
@KenBourassa 你所说的不会改变大卫所说的。 “您需要让线程在终止时通知您...使用
OnTerminate来通知” 但是请注意,线程可以覆盖@ 987654343@ 触发OnTerminate没有 使用TThread.Synchronize()(我有线程可以做到这一点),因此重新引入线程引用的竞争条件,如果你说不可能发生你使用OnTerminate。但这是一种更高级的用法,大多数人大部分时间都不太可能这样做,在这种情况下,你说的就行了。 -
@RemyLebeau 我从未质疑过大卫的那部分观点。我质疑如果说线程是 FreeOnTerminate 则不能使用线程引用的概念,这是错误的。至于你的第二点,是的,我想你可以覆盖
TThread.DoTerminate()来调用OnTerminate而没有TThread.Synchronize()。考虑到TThread.OnTerminate被明确记录为在主线程的上下文中执行,我们不再谈论 TThread,我们谈论的是TYourThread。但由于它违反了 TThread 引入的“合同”,我将为此引入一个新事件。
标签: multithreading delphi delphi-10.4-sydney