在 Delphi 中释放 TCriticalSection 对象的正确方法

Mat*_*ini 1 delphi multithreading

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

initialization
  FPoolingCS := TCriticalSection.Create;
Run Code Online (Sandbox Code Playgroud)
finalization
  FPoolingCS.Acquire;
  FreeAndNil(FPoolingCS);
Run Code Online (Sandbox Code Playgroud)

我应该ReleaseFree?之前调用该方法?

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

Dal*_*kar 8

由于多种原因,这不是释放临界区的正确方法。

根据文档EnterCriticalSection 函数

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

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

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

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

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

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

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

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

  • +1。理想情况下,如果有工作线程,它们应该提供某种机制来优雅地停止。应用程序的干净关闭首先会等待并确认所有未完成的线程已完成执行,然后再释放它们所依赖的共享对象(例如临界区等)。 (2认同)