读写器并发

时间:2017-06-20 08:00:36

标签: c multithreading gcc concurrency pthreads

我正在尝试实现以下方案。如果系统中只有读者,请不要使用互斥锁。我写了以下实现。

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:同时添加了解锁码。

1 个答案:

答案 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);
}