首页 > 解决方案 > 在 Delphi 中释放 TCriticalSection 对象的正确方法

问题描述

这是释放TCriticalSection在 Delphi 的初始化部分中创建的对象的正确方法吗?

initialization
  FPoolingCS := TCriticalSection.Create;
finalization
  FPoolingCS.Acquire;
  FreeAndNil(FPoolingCS);

我应该在 之前调用该Release方法Free吗?

Acquire方法会抛出一些我需要处理的异常吗?

标签: multithreadingdelphi

解决方案


由于几个原因,这不是释放关键部分的正确方法。

根据文档EnterCriticalSection 功能

如果对关键部分的等待操作超时,此函数可以引发 EXCEPTION_POSSIBLE_DEADLOCK。超时间隔由以下注册表值指定:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\CriticalSectionTimeout。不处理可能的死锁异常;相反,调试应用程序。

如果一个临界区在它仍然拥有的时候被删除,那么等待被删除临界区所有权的线程的状态是未定义的。

当进程退出时,如果对 EnterCriticalSection 的调用会阻塞,它将立即终止进程。这可能会导致不调用全局析构函数。

FPoolingCS.Acquire在 Windows 平台调用函数EnterCriticalSection。所以第一个问题,获取临界区是否会引发异常,答案是肯定的。

同样根据文档,您不应该尝试处理此类异常,但您必须调试应用程序,因为问题的根源在于其他一些代码。

但是,在任何平台上释放临界区实例之前不应调用的最显着原因Acquire是,如果此时有一些其他线程正在做一些工作并且依赖于该临界区,则意味着您的关闭和清理过程完全被破坏. 换句话说,如果Acquire解决了您的问题,真正的问题在另一座城堡中,而您还没有真正解决任何问题,您只是稍微改变了动态,这可能有效也可能无效,具体取决于所涉及的所有其他代码。

Release出于同样的原因,之前调用Free将毫无意义。如果还有其他涉及的线程仍在运行,它们可能会在Free执行之前获取锁。

只需调用Free关键部分,或者如果你喜欢使用FreeAndNil它,如果你的关闭过程被破坏,它最终会崩溃。请记住,线程问题并不能始终如一地重现,因此没有崩溃仍然不意味着您拥有完全没有错误的代码。


推荐阅读