【发布时间】:2020-10-18 05:37:39
【问题描述】:
Slim Reader/Writer (SRW) Locks 是 Windows 中的同步原语,从 Windows Vista 开始可用。
名称和接口表明它应该用作非定时共享非递归互斥锁。但是,通常也将其用作非共享互斥体,以避免 CRTICAL_SECTION 开销(仅使用独占 API)。
我注意到它也可以用作二进制信号量。这可以派上用场,因为 Windows API 中可用的其他信号量 - 事件对象和信号量对象 - 始终是内核调用,因此它可能是唯一可从 Windows API 轻松获得的轻量级信号量(并且 C++ 具有从 C++20 开始的信号量,并且boost 线程也不提供信号量)。
但这可靠吗?具体来说,我在文档中没有找到可以这样使用的明确信息。
但是,我没有发现任何禁止这种用法的东西。文档似乎不确定。
我期望的答案是什么:
- 也许有人可以指出允许或禁止使用信号量的文档措辞
- 也许有这种用法的一些实际经验
- 也许直接参与 SRW 锁实现的人可以澄清(我认为有一些机会)
示例 - 这不会挂起
#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;
}
【问题讨论】:
-
也可用作二进制信号量。 - 你的意思是什么?说代码示例
-
@RbMm,我添加了一个示例。大多数情况下,我的意思是
AcquireSRWLockExclusive和ReleaseSRWLockExclusive可以从任意线程调用,只要没有与现有AcquireSRWLockExclusive不匹配的ReleaseSRWLockExclusive -
首先你需要
can_release = true;在::AcquireSRWLockExclusive(&lock);之后而不是之前。如果从代码意义上讲,您尝试做什么?将 SRW 的所有权从一个线程转移到另一个线程?在某个线程中调用AcquireSRWLockExclusive(&lock)并匹配另一个线程中的AcquireSRWLockExclusive?是的,这可能,尽管不寻常 -
只有获得的线程才能释放。违反此规则会调用未定义的行为。这是由应用程序验证者强制执行的。如果你只想要一个轻量级的信号量,你可以使用 WaitOnAddress。
-
按照合约编写代码比编写实现代码要好得多。
标签: winapi semaphore readwritelock