我想围绕一段复杂的多线程代码编写一些断言。有没有办法做一个
assert(GetCurrentThreadId() == ThreadOfCriticalSection(sec));
我想围绕一段复杂的多线程代码编写一些断言。有没有办法做一个
assert(GetCurrentThreadId() == ThreadOfCriticalSection(sec));
如果您想正确执行此操作,我认为您在关键部分周围使用了一个包装器对象,它将跟踪哪个线程(如果有)在调试版本中拥有每个 CS。
即,不是直接调用 EnterCriticalSection,而是调用包装器上的一个方法,该方法执行 EnterCriticalSection,然后,当它成功时,将 GetCurrentThreadId 存储在断言将检查的 DWORD 中。另一种方法是在调用 LeaveCriticalSection 之前将该线程 ID DWORD 归零。
(在发布版本中,包装器可能会省略额外的东西,只调用 Enter/LeaveCriticalSection。)
正如 Casablanca 指出的那样,所有者线程 ID 位于当前的 CRITICAL_SECTION 结构中,因此使用我建议的包装器将存储冗余信息。但是,正如 Casablanca 还指出的那样,CRITICAL_SECTION 结构不是任何 API 合同的一部分,并且可能会发生变化。(事实上,它在过去的 Windows 版本中已经改变。)
了解内部结构对调试很有用,但不应在生产代码中使用。
所以你使用哪种方法取决于你希望你的解决方案有多“合适”。如果您只想在当前版本的 Windows 上使用一些临时断言来追踪问题,那么直接使用 CRITICAL_SECTION 字段对我来说似乎是合理的。只是不要指望这些断言永远有效。如果你想要一些可以持续更长时间的东西,请使用包装器。
(使用包装器的另一个优点是您将获得 RAII。即包装器的构造函数和析构函数将处理 InitializeCriticalSection 和 DeleteCriticalSection 调用,因此您不再需要担心它们。说到这一点,我发现它非常有用有一个辅助对象,它在构造时进入 CS,然后在销毁时自动离开它。没有更多的关键部分意外锁定,因为函数中间隐藏了早期返回......)
据我所知,没有记录的方式来获取这些信息。如果您查看标题,该CRITICAL_SECTION
结构包含一个线程句柄,但我不会依赖这些信息,因为内部结构可能会在没有通知的情况下发生变化。更好的方法是在线程进入/退出临界区时自己维护这些信息。
你的要求没有意义。如果你当前的线程不是临界区的线程,那么当前线程中的代码将不会运行,当试图锁定临界区时它会被阻塞。
如果您的线程实际上在关键部分内,那么您的断言将始终为真。如果不是,您的断言将永远是错误的!
所以我的意思是,假设你能够跟踪哪个线程在临界区,如果你把你的断言放在临界区代码中,它总是正确的。如果你把它放在外面,它总是假的。