我正在尝试实现以下方案。如果系统中只有读者,请不要使用互斥锁。我写了以下实现。
LockReader()
{
flag = 0;
atomic increment cntReader;
if(atomic check cntWriter > 0)
{
while(noLock != 0);
flag = 1;
mutexLock(var);
}
else
{
atomic increment noLock;
}
//CS
if(flag == 1)
mutexUnlock(var);
else
atomic decrement noLock;
atomic decrement cntReader;
}
LockWriter()
{
atomic increment cntWriter;
if(atomic check cntReader > 0)
{
while(noLock != 0);
}
mutexLock(var);
mutexUnlock(var);
atomic decrement cntWriter;
}
但是这段代码有一个问题,如果有一个读者,并且在评估了LockShared(if(cntWriter > 1)
)的第3行并且编写器来之后它获得了上下文切换,那么它可以得到mutexLock,因为noLock不是增加了。在mutexLock之后,如果writer被上下文切换,读者也将被允许。我们让读者和作家都在一起。
如何避免这种情况?
编辑1: 我用这种方式更改了LockReader():
LockReader()
{
flag = 0;
atomic increment cntReader;
atomic increment noLock;
if(atomic check cntWriter > 0)
{
atomic decrement noLock;
while(noLock != 0);
flag = 1;
mutexLock(var);
}
//CS
if(flag == 1)
mutexUnlock(var);
else
atomic decrement noLock;
atomic decrement cntReader;
}
我认为这应该解决我提到的问题。但是否有其他读写器并发问题可能吗?
编辑2:同时添加了解锁码。
答案 0 :(得分:0)
如果完全与性能有关,则根本不应使用互斥锁。而是只使用一个计数器并忙着等待,即:
volatile int rw_lock;
LockReader() {
int l, success = 0;
while (success == 0) {
l = rw_lock;
if (l < 0) {
// wait for a writer
continue;
}
// atomically increment rw_lock
success == cmpset(rw_lock, l, l + 1);
}
}
LockWriter() {
int l, success = 0;
while (success == 0) {
l = rw_lock;
if (l != 0) {
// wait for readers
continue;
}
// atomically set rw_lock to -1
success = cmpset(rw_lock, 0, -1);
}
}
UnlockReader() {
atomic_dec(rw_lock);
}
UnlockWriter() {
atomic_inc(rw_lock);
}
这些类型的锁称为读写器锁。您可以在维基百科上找到更多信息:
https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
编辑: 写优先版:
volatile int rw_lock;
volatile int w_req;
LockReader() {
int l, success = 0;
while (success == 0) {
while (w_req) {
// wait due to write preference
}
l = rw_lock;
if (l < 0) {
// wait for a writer
continue;
}
// atomically increment rw_lock
success == cmpset(rw_lock, l, l + 1);
}
}
LockWriter() {
int l, success = 0;
w_req = 1; // request a write, i.e. block new reads
while (success == 0) {
l = rw_lock;
if (l != 0) {
// wait for readers
continue;
}
// atomically set rw_lock to -1
success = cmpset(rw_lock, 0, -1);
}
w_req = 0; // allow new reads
}
UnlockReader() {
atomic_dec(rw_lock);
}
UnlockWriter() {
atomic_inc(rw_lock);
}