【问题标题】:Reader-writer concurrency读写器并发
【发布时间】:2017-11-22 15:39:13
【问题描述】:

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

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 行之后它获得了上下文切换并且写入器来了,那么它可以获得互斥锁,因为 noLock 还没有增加.并且在互斥锁之后,如果写者被上下文切换,读者也将被允许。我们让读者和作家在一起。

如何避免这种情况?

编辑 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:也添加了解锁代码。

【问题讨论】:

  • 您为什么要这样做?非竞争锁的获取成本不应该很高。似乎是错误的优化。
  • 为了完整起见,能否提供相应的解锁功能?
  • @JohnZwinck 我正在努力提高性能。即使对读者采取独占互斥锁也会严重降低性能。
  • @AndriyBerestovskyy 已添加。

标签: c multithreading gcc concurrency pthreads


【解决方案1】:

如果只考虑性能,则根本不应该使用互斥锁。而是只使用一个计数器并忙于等待,即:

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

这种类型的锁称为读写锁。您可以在 Wikipedia 上找到更多信息:

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

【讨论】:

  • 我无法使用__sync_val_compare_and_swap,因为产品支持的gcc是4.3.4
  • 另外,代码会导致作者饿死吗?我的观察对吗?
  • @user2761431 1. 你需要 __sync_bool_compare_and_swap 并且它应该在 gcc 4.3.4 中可用 2. 请参考维基百科链接,有写优先 RW 锁。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多