Dan*_*enc 9 c++ winapi multithreading critical-section
我必须使用Win32 api在C++中实现读/写锁,作为工作项目的一部分.所有现有解决方案都使用在执行期间需要上下文切换的内核对象(信号量和互斥量).这对我的申请来说太慢了.
如果可能的话,我想只使用关键部分实现一个.锁不必是过程安全的,只有线程安全.关于如何解决这个问题的任何想法?
我不认为这可以在不使用至少一个内核级对象(Mutex或Semaphore)的情况下完成,因为您需要内核的帮助来调用进程块直到锁可用.
关键部分确实提供了阻止,但API太有限了.例如,您无法获取CS,发现读取锁定可用而不是写入锁定,并等待其他进程完成读取(因为如果其他进程具有关键部分,则会阻止其他读取器出错,如果它没有那么你的进程不会阻止但是旋转,燃烧CPU周期.)
但是,你可以做的是使用自旋锁,并在有争用时回退到互斥锁.关键部分本身就是这样实现的.我将采用现有的临界区实现,并将PID字段替换为单独的读写器计数.
老问题,但这是应该工作的东西.它不会引发争论.如果读者很少或没有争用,读者会产生有限的额外费用,因为它SetEvent被称为懒惰(请查看没有此优化的更重量级版本的编辑历史记录).
#include <windows.h>
typedef struct _RW_LOCK {
CRITICAL_SECTION countsLock;
CRITICAL_SECTION writerLock;
HANDLE noReaders;
int readerCount;
BOOL waitingWriter;
} RW_LOCK, *PRW_LOCK;
void rwlock_init(PRW_LOCK rwlock)
{
InitializeCriticalSection(&rwlock->writerLock);
InitializeCriticalSection(&rwlock->countsLock);
/*
* Could use a semaphore as well. There can only be one waiter ever,
* so I'm showing an auto-reset event here.
*/
rwlock->noReaders = CreateEvent (NULL, FALSE, FALSE, NULL);
}
void rwlock_rdlock(PRW_LOCK rwlock)
{
/*
* We need to lock the writerLock too, otherwise a writer could
* do the whole of rwlock_wrlock after the readerCount changed
* from 0 to 1, but before the event was reset.
*/
EnterCriticalSection(&rwlock->writerLock);
EnterCriticalSection(&rwlock->countsLock);
++rwlock->readerCount;
LeaveCriticalSection(&rwlock->countsLock);
LeaveCriticalSection(&rwlock->writerLock);
}
int rwlock_wrlock(PRW_LOCK rwlock)
{
EnterCriticalSection(&rwlock->writerLock);
/*
* readerCount cannot become non-zero within the writerLock CS,
* but it can become zero...
*/
if (rwlock->readerCount > 0) {
EnterCriticalSection(&rwlock->countsLock);
/* ... so test it again. */
if (rwlock->readerCount > 0) {
rwlock->waitingWriter = TRUE;
LeaveCriticalSection(&rwlock->countsLock);
WaitForSingleObject(rwlock->noReaders, INFINITE);
} else {
/* How lucky, no need to wait. */
LeaveCriticalSection(&rwlock->countsLock);
}
}
/* writerLock remains locked. */
}
void rwlock_rdunlock(PRW_LOCK rwlock)
{
EnterCriticalSection(&rwlock->countsLock);
assert (rwlock->readerCount > 0);
if (--rwlock->readerCount == 0) {
if (rwlock->waitingWriter) {
/*
* Clear waitingWriter here to avoid taking countsLock
* again in wrlock.
*/
rwlock->waitingWriter = FALSE;
SetEvent(rwlock->noReaders);
}
}
LeaveCriticalSection(&rwlock->countsLock);
}
void rwlock_wrunlock(PRW_LOCK rwlock)
{
LeaveCriticalSection(&rwlock->writerLock);
}
Run Code Online (Sandbox Code Playgroud)
您可以通过使用单个来降低读者的成本CRITICAL_SECTION:
countsLock被替换为writerLock在rdlock和rdunlock
rwlock->waitingWriter = FALSE 在wrunlock被删除
wrlock的身体变成了
EnterCriticalSection(&rwlock->writerLock);
rwlock->waitingWriter = TRUE;
while (rwlock->readerCount > 0) {
LeaveCriticalSection(&rwlock->writerLock);
WaitForSingleObject(rwlock->noReaders, INFINITE);
EnterCriticalSection(&rwlock->writerLock);
}
rwlock->waitingWriter = FALSE;
/* writerLock remains locked. */
Run Code Online (Sandbox Code Playgroud)然而,这种损失是公平的,所以我更喜欢上述解决方案.
| 归档时间: |
|
| 查看次数: |
14583 次 |
| 最近记录: |