SRW Lock可以作为二进制信号量使用吗?
Can SRW Lock be used as a binary semaphore?
Slim Reader/Writer (SRW) Locks 是 Windows 中的同步原语,从 Windows Vista 开始可用。
名称和接口表明它应该用作非定时共享非递归互斥体。但是,通常也将其用作非共享互斥锁,以避免 CRTICAL_SECTION
开销(仅使用独占 APIs)。
我注意到它也可以用作二进制信号量。这可以派上用场,因为 Windows APIs 中可用的其他信号量 - 事件对象和信号量对象 - 始终是内核调用,因此它可能是 Windows 中唯一可用的轻量级信号量API(C++20开始有信号量,boost线程也不提供信号量)
但这靠谱吗?具体来说,我没有在文档中找到明确的信息可以这样使用。
但是,我还没有发现任何禁止这种用法的东西。文档似乎不确定。
我期待的答案:
- 也许有人可以指出允许或禁止使用信号量的文档措辞
- 也许这样的用法有一些实践经验
- 也许直接参与 SRW 锁实现的人可以澄清(我认为有一些机会)
示例 - 这不会挂起[=13=]
#include <Windows.h>
#include <atomic>
SRWLOCK lock = SRWLOCK_INIT;
std::atomic<bool> can_release{ false };
DWORD CALLBACK Thread1(LPVOID)
{
for (int i = 0; i < 3; i++)
{
while (!can_release)
{
// spin
}
can_release = false;
::ReleaseSRWLockExclusive(&lock);
}
return 0;
}
DWORD CALLBACK Thread2(LPVOID)
{
for (int i = 0; i < 3; i++)
{
can_release = true;
::AcquireSRWLockExclusive(&lock);
}
return 0;
}
int main() {
::AcquireSRWLockExclusive(&lock);
HANDLE h1 = ::CreateThread(nullptr, 0, Thread1, nullptr, 0, nullptr);
HANDLE h2 = ::CreateThread(nullptr, 0, Thread2, nullptr, 0, nullptr);
::WaitForSingleObject(h1, INFINITE);
::WaitForSingleObject(h2, INFINITE);
::CloseHandle(h1);
::CloseHandle(h2);
return 0;
}
@Raymond Chen 说的对。应用程序验证程序报告有关代码的错误:
有问题的代码产生了这个错误:
=======================================
VERIFIER STOP 0000000000000255: pid 0x1A44: The SRW lock being released was not acquired by this thread.
00007FF73979C170 : SRW Lock
00000000000025CC : Current ThreadId.
00000000000043F4 : ThreadId of the thread that acquired the SRW lock.
000001C1BEA8BF40 : Address of the acquire stack trace. Use dps <address> to see where the SRW lock was acquired.
=======================================
This verifier stop is continuable.
After debugging it use `go' to continue.
=======================================
=======================================
VERIFIER STOP 0000000000000253: pid 0x1A44: The SRW lock is being acquired recursively by the same thread.
00007FF73979C170 : SRW Lock
000001C1BEA8BF40 : Address of the first acquire stack trace. Use dps <address> to see where the SRW lock was acquired.
0000000000000000 : Not used
0000000000000000 : Not used
=======================================
This verifier stop is continuable.
After debugging it use `go' to continue.
=======================================
截至目前,文档还明确禁止在不同的线程中发布,参见 ReleaseSRWLockExclusive, ReleaseSRWLockShared:
The SRW lock must be released by the same thread that acquired it. You can use Application Verifier to help verify that your program uses SRW locks correctly (enable Locks checker from Basic group).
Slim Reader/Writer (SRW) Locks 是 Windows 中的同步原语,从 Windows Vista 开始可用。
名称和接口表明它应该用作非定时共享非递归互斥体。但是,通常也将其用作非共享互斥锁,以避免 CRTICAL_SECTION
开销(仅使用独占 APIs)。
我注意到它也可以用作二进制信号量。这可以派上用场,因为 Windows APIs 中可用的其他信号量 - 事件对象和信号量对象 - 始终是内核调用,因此它可能是 Windows 中唯一可用的轻量级信号量API(C++20开始有信号量,boost线程也不提供信号量)
但这靠谱吗?具体来说,我没有在文档中找到明确的信息可以这样使用。
但是,我还没有发现任何禁止这种用法的东西。文档似乎不确定。
我期待的答案:
- 也许有人可以指出允许或禁止使用信号量的文档措辞
- 也许这样的用法有一些实践经验
- 也许直接参与 SRW 锁实现的人可以澄清(我认为有一些机会)
示例 - 这不会挂起[=13=]
#include <Windows.h>
#include <atomic>
SRWLOCK lock = SRWLOCK_INIT;
std::atomic<bool> can_release{ false };
DWORD CALLBACK Thread1(LPVOID)
{
for (int i = 0; i < 3; i++)
{
while (!can_release)
{
// spin
}
can_release = false;
::ReleaseSRWLockExclusive(&lock);
}
return 0;
}
DWORD CALLBACK Thread2(LPVOID)
{
for (int i = 0; i < 3; i++)
{
can_release = true;
::AcquireSRWLockExclusive(&lock);
}
return 0;
}
int main() {
::AcquireSRWLockExclusive(&lock);
HANDLE h1 = ::CreateThread(nullptr, 0, Thread1, nullptr, 0, nullptr);
HANDLE h2 = ::CreateThread(nullptr, 0, Thread2, nullptr, 0, nullptr);
::WaitForSingleObject(h1, INFINITE);
::WaitForSingleObject(h2, INFINITE);
::CloseHandle(h1);
::CloseHandle(h2);
return 0;
}
@Raymond Chen 说的对。应用程序验证程序报告有关代码的错误:
有问题的代码产生了这个错误:
=======================================
VERIFIER STOP 0000000000000255: pid 0x1A44: The SRW lock being released was not acquired by this thread.
00007FF73979C170 : SRW Lock
00000000000025CC : Current ThreadId.
00000000000043F4 : ThreadId of the thread that acquired the SRW lock.
000001C1BEA8BF40 : Address of the acquire stack trace. Use dps <address> to see where the SRW lock was acquired.
=======================================
This verifier stop is continuable.
After debugging it use `go' to continue.
=======================================
=======================================
VERIFIER STOP 0000000000000253: pid 0x1A44: The SRW lock is being acquired recursively by the same thread.
00007FF73979C170 : SRW Lock
000001C1BEA8BF40 : Address of the first acquire stack trace. Use dps <address> to see where the SRW lock was acquired.
0000000000000000 : Not used
0000000000000000 : Not used
=======================================
This verifier stop is continuable.
After debugging it use `go' to continue.
=======================================
截至目前,文档还明确禁止在不同的线程中发布,参见 ReleaseSRWLockExclusive, ReleaseSRWLockShared:
The SRW lock must be released by the same thread that acquired it. You can use Application Verifier to help verify that your program uses SRW locks correctly (enable Locks checker from Basic group).