是TThread.Synchronize evil / stillborn吗?

时间:2017-04-28 12:59:12

标签: multithreading delphi synchronization

我得到一个印象,一个应该至少可以从主线程控制的线程一定不能使用Synchronize():任何尝试这样做几乎会立即导致一个或另一个案件出现死锁。

因此,应该避免onTerminate事件,因为它使用Synchronize调用。

例如,我有一个线程,它做了一些艰苦的背景工作。我希望看到它在状态栏中的进展,并且能够优雅地停止它并且#39;如果用户按下关闭按钮。

我不能使用FreeOnTerminate := true,因为在线程启动时我根本不能调用它的任何方法:它可能随时被销毁而且我得到访问冲突(或完全损坏了某些东西)

因此,线程破坏是主线索的责任。完成所有'整理'是合乎逻辑的。在某种DoTerminate过程中工作并指向onTerminate事件。但是那个死锁:我们无法从DoTerminate释放线程,因为在TThread.Free中有WaitFor,在同步onTerminate事件结束之前无法完成。

不仅仅是OnTerminate:如果工作线程中有任何Synchronize调用(例如,它想通知我们已经完成了一些工作的百分比等),那么如果此时主线程正在进行,就有可能出现死锁用工作线程做smth:他们互相阻挡!

因此,根据我的理解,使用Synchronize的唯一方法是将所有调用委托给工作线程端!例如,我们使用FreeOnTerminate := true创建它,它有时会使用Synchronize()告诉我们它的进度,或者它已经完成并将被销毁。只有在这些程序中,我们才能控制它,但它可以随意关闭'几乎不可能或过于复杂。

我错过了什么(一些内部工作有助于以某种方式克服这些死锁)?因为我有点惊讶:Synchronize()是Delphi多线程手册中描述的第一个方法之一。它真的没用吗?

1 个答案:

答案 0 :(得分:9)

Synchronize有完全有效的用例,但您必须小心识别这些用例是什么,并确保编写代码以便明确避免出现死锁情况。这是完全可能的,但需要仔细设计。

当您需要工作线程等待主线程在继续之前完成工作时,通常只应使用Synchronize。在大多数情况下,这不是必需的,通常应优先使用TThread.Queue。使用Queue将工作发布到主线程,但随后立即返回,而不等待主线程处理工作。这避免了围绕使用Synchronize的大多数死锁陷阱。

Queue唯一的危险是重载主线程。如果你的工作者主要向主线程发布工作的速度比主线程能够跟上的速度快,那么你最终可能会遇到主线程锁定处理排队工作的情况。