⚙️ 工程
跨进程读写锁开发(一):信号量Developing a cross-process reader/writer lock with limited readers, part 1: A semaphore
微软 Raymond Chen 撰写系列文章讲解如何构建一个支持有限读者的跨进程读写锁。本部分介绍使用 Windows 信号量(semaphore)作为基础同步原语的设计思路,解决多个进程间协调读/写访问共享资源的问题。这是实现高性能并发控制的关键第一步。
Raymond Chen
假设你想要实现一个跨进程的读写锁功能,但内置的 SRWLOCK 只能在单个进程内工作。那么,我们能否构建一个支持跨进程的读写锁呢?
为方便说明,假设我们希望最多允许 N 个读者同时读取(N 是一个固定值)。我们可以这样实现:
写锁的设计思路是:通过占用所有读锁所需的资源(即全部 N 个令牌),确保其他进程无法再获取任何读锁。
#define MAX_SHARED 100
HANDLE sharedSemaphore;
void AcquireShared()
{
WaitForSingleObject(sharedSemaphore, INFINITE);
}
void ReleaseShared()
{
ReleaseSemaphore(sharedSemaphore, 1, nullptr);
}
void AcquireExclusive()
{
for (unsigned i = 0; i < MAX_SHARED; i++) {
WaitForSingleObject(sharedSemaphore, INFINITE);
}
}
void ReleaseShared()
{
ReleaseSemaphore(sharedSemaphore, MAX_SHARED, nullptr);
}由于使用了 WaitForSingleObject 函数,我们还可以设置超时机制,让调用者在无法获取锁时选择放弃操作。
bool AcquireSharedWithTimeout(DWORD timeout)
{
return WaitForSingleObject(sharedSemaphore, timeout) == WAIT_OBJECT_0;
}
bool AcquireExclusiveWithTimeout(DWORD timeout)
{
DWORD start = GetTickCount();
for (unsigned i = 0; i < MAX_SHARED; i++) {
DWORD elapsed = GetTickCount() - start;
if (elapsed > timeout ||
WaitForSingleObject(sharedSemaphore, timeout - elapsed) == WAIT_TIMEOUT)) {
// Restore the tokens we already claimed.
if (i > 0) {
ReleaseSemaphore(sharedSemaphore, i, nullptr);
}
return false;
}
}
return true;
}独占获取(写锁)较为复杂,因为需要多次调用 WaitForSingleObject,且每次等待时间递减。如果最终超时,则必须提前归还已申请的令牌。
不过,这里仍然存在一个问题,我们将在下次讨论。
作者
Raymond 在 Windows 系统演进过程中已有超过 30 年的参与经验。自 2003 年起,他运营了一个名为 The Old New Thing 的网站,其受欢迎程度远超他的想象,至今仍让他感到些许不安。该网站催生了一本同名书籍《The Old New Thing》(Addison Wesley, 2007)。他偶尔也会出现在 Windows Dev Docs 的 Twitter 账号上,讲述一些毫无实用价值的故事。
需要完整排版与评论请前往来源站点阅读。