ReleaseSemaphore() 会阻塞吗?
can ReleaseSemaphore() ever block?
我在 WIN32 上有一个多线程应用程序 运行ning,它使用信号量来保护链表。偶尔会出现这种锁定。当它锁定时,我可以在 Visual Studio 代码下的 cppvsdbg
中停止应用程序,我可以看到其中两个线程正在等待信号量,即它们被阻塞在:
WaitForSingleObject(handle, INFINITE);
然而,第三个线程在这里被阻塞了:
ReleaseSemaphore(handle, 1, NULL);
...即它似乎在 ReleaseSemaphore()
上阻塞了,这个函数当然会允许其他两个线程之一 运行。如果我在调试器中单步执行,或者我在 ReleaseSemaphore()
调用之后设置了一个断点并继续 运行ning,没有任何变化,应用程序仍然处于锁定状态。在 ReleaseSemaphore()
阻塞的线程 运行ning 的优先级为 0,其他两个线程的优先级为 0 和 -1,所以我看不出线程优先级如何导致问题。
不仅如此,我不明白为什么ReleaseSemaphore()
在任何情况下都会阻塞。 handle
的值是 0x000000ec,这是当天开始时的值,所以 handle
的值没有被破坏,虽然我猜 [=43= handle
的 ]contents 可能被弄乱了……?不确定我将如何调试它。
对于 ReleaseSemaphore()
为何会锁定,或者出现问题时我可能会在调试器中查看哪些其他内容以确定发生了什么,有人有任何建议吗?
编辑:代码是用 /Od
编译的,以避免视觉调试和代码之间的任何错位,这是 cppvsdbg
window 显示的屏幕截图似乎在 ReleaseSemaphore()
:
上被阻塞的线程
正确答案是:不,Win32 API 函数 ReleaseSemaphore()
永远不会阻塞。
在这种情况下 出现 阻塞的原因是,另外,我们需要在 Windows 上模拟关键部分(回想一下这段代码通常运行在RTOS 上的嵌入式系统,Windows 仅用于快速开发)。为了模拟 Windows 上的临界区,我们在除当前线程之外的所有线程上调用 SuspendThread()
(以及后来的 ResumeThread()
)。当这样一个模拟的关键部分就位时,代码中的 其他地方 发生了故障,而且碰巧这与大多数时间的 ReleaseSemaphore()
调用同时发生,使其成为看起来好像 ReleaseSemaphore()
被阻止了;没有,线程恰好挂在那里。
所以我们只需修复另一个错误,这个明显的问题就消失了。
我在 WIN32 上有一个多线程应用程序 运行ning,它使用信号量来保护链表。偶尔会出现这种锁定。当它锁定时,我可以在 Visual Studio 代码下的 cppvsdbg
中停止应用程序,我可以看到其中两个线程正在等待信号量,即它们被阻塞在:
WaitForSingleObject(handle, INFINITE);
然而,第三个线程在这里被阻塞了:
ReleaseSemaphore(handle, 1, NULL);
...即它似乎在 ReleaseSemaphore()
上阻塞了,这个函数当然会允许其他两个线程之一 运行。如果我在调试器中单步执行,或者我在 ReleaseSemaphore()
调用之后设置了一个断点并继续 运行ning,没有任何变化,应用程序仍然处于锁定状态。在 ReleaseSemaphore()
阻塞的线程 运行ning 的优先级为 0,其他两个线程的优先级为 0 和 -1,所以我看不出线程优先级如何导致问题。
不仅如此,我不明白为什么ReleaseSemaphore()
在任何情况下都会阻塞。 handle
的值是 0x000000ec,这是当天开始时的值,所以 handle
的值没有被破坏,虽然我猜 [=43= handle
的 ]contents 可能被弄乱了……?不确定我将如何调试它。
对于 ReleaseSemaphore()
为何会锁定,或者出现问题时我可能会在调试器中查看哪些其他内容以确定发生了什么,有人有任何建议吗?
编辑:代码是用 /Od
编译的,以避免视觉调试和代码之间的任何错位,这是 cppvsdbg
window 显示的屏幕截图似乎在 ReleaseSemaphore()
:
正确答案是:不,Win32 API 函数 ReleaseSemaphore()
永远不会阻塞。
在这种情况下 出现 阻塞的原因是,另外,我们需要在 Windows 上模拟关键部分(回想一下这段代码通常运行在RTOS 上的嵌入式系统,Windows 仅用于快速开发)。为了模拟 Windows 上的临界区,我们在除当前线程之外的所有线程上调用 SuspendThread()
(以及后来的 ResumeThread()
)。当这样一个模拟的关键部分就位时,代码中的 其他地方 发生了故障,而且碰巧这与大多数时间的 ReleaseSemaphore()
调用同时发生,使其成为看起来好像 ReleaseSemaphore()
被阻止了;没有,线程恰好挂在那里。
所以我们只需修复另一个错误,这个明显的问题就消失了。