应用验证程序报告“线程不能拥有关键部分”。

Posted

技术标签:

【中文标题】应用验证程序报告“线程不能拥有关键部分”。【英文标题】:App Verifier reporting "Thread cannot own a critical section." 【发布时间】:2009-05-28 13:08:26 【问题描述】:

所以 App Verifier 抛出了这个异常。据我所知,这条消息的文字有点误导。问题似乎是临界区是由在临界区被销毁之前被销毁的线程创建的。

这是一个相对简单的修复,但有谁知道创建线程以外的线程破坏关键部分的后果是什么?它有多危险?只是担心临界区句柄会“泄漏”还是存在更隐蔽的副作用?

其他一些信息:

用 C++ 编写的应用程序(当然是在 Windows 上) 使用 InitializeCriticalSelection 创建的关键部分 最终使用 DeleteCriticalSection 删除关键部分

【问题讨论】:

【参考方案1】:

我相信您对消息的解释是正确的。我能找到的唯一参考如下。正如作者建议的那样,堆栈跟踪是一个很好的线索

http://jpassing.wordpress.com/2008/02/18/application-verifier-thread-cannot-own-a-critical-section/

我挖了一会儿,找不到任何具体原因为什么不能在不同线程上创建和删除关键部分。但是我确实想知道您为什么要这样做?可以这么说,让一个线程拥有一个关键部分似乎是最佳实践。在线程之间切换临界区引入了另一种通信方式和潜在的错误(可以做到,只是更有趣)。

【讨论】:

是的,我同意。这是不可取的,如果存在有害的副作用,它将对代码进行更改,但我正在查看的代码很脆弱,如果可以避免,现在不应该更改。感谢您的意见!【参考方案2】:

似乎已接受的答案谈论创建关键部分,这不是此消息的内容。 Eran 的回答涵盖了消息的真正原因,但这里是 TL;DR 术语:

应用程序验证程序检测到一个线程,该线程已获得临界区锁,正在尝试退出而该部分仍处于锁定状态

它没有抱怨线程创建 临界区并且现在正在终止。这与谁创建和销毁该部分无关。线程拥有该关键部分上的锁并终止,这是非常合理的抱怨。他们本可以使该信息的措辞更加清晰。

【讨论】:

【参考方案3】:

与 COM 对象等野兽相反,临界区生命周期并不绑定到某个线程。关键部分的构建分为两个阶段:在创建时,它们仅由几个结构组成。在两个或更多线程争用时,会创建一个内核互斥锁以正确处理同步。任何线程都可以创建、访问和破坏结构体和互斥体,无论是否创建了临界区。

要回答您的问题,上述内容意味着您应该可以毫无问题地在一个线程中创建 CS 并在另一个线程中销毁它。然而,这可能意味着设计存在一些问题。如果您还没有这样做,请考虑将 CS 包装在一个类中,该类将在其构造函数中初始化 CS,并在其析构函数中销毁它(MFC 的 CCriticalSection 会这样做)。然后,在比使用它的范围更高的范围内创建包装器(全局、静态类成员等)。应该使创建和清理更容易。

最后,关于错误消息本身 - 被删除的线程是否可能已经进入 CS 而没有机会离开它(由于异常等)?如果是这种情况,您会收到一条看起来很奇怪的消息,指出存在真正的问题。

【讨论】:

@eran,我同意你关于设计性质的所有观点。正如我之前所说,这是代码中一个相对脆弱的区域,这不是我目前工作的重点,我不想无意中破坏它 - 所以如果我能避免它,现在设计更改。感谢您深入了解关键部分的内部工作方式。 我听到了...如果可能的话,您可以使用这些技术来创建仅用于定位这一问题的本地构建。尝试使用 Enter() 和 Leave() 方法创建一个包装器,这也会设置一个状态标志。在 d'tor 上,断言标志是否未调用 Leave()。这样您就可以定位 CS 出口点,并在您的原始代码中添加 try-catch 或另一个 LeaveCriticalSection。

以上是关于应用验证程序报告“线程不能拥有关键部分”。的主要内容,如果未能解决你的问题,请参考以下文章

RandomStr实验报告(验证码实验)

macOS Catalina 上的应用程序“无法打开,因为无法验证其完整性”

Python程序设计实验报告二:顺序结构程序设计(验证性实验)

Python程序设计实验报告二:顺序结构程序设计(验证性实验)

在 Python 中收集和报告多个异常的惯用方式

java登陆界面实验报告