我正在尝试使用shared_mutex在C++中使用读/写锁

typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock >  WriteLock;
typedef boost::shared_lock< Lock >  ReadLock;

class Test {
    Lock lock;
    WriteLock writeLock;
    ReadLock readLock;

    Test() : writeLock(lock), readLock(lock) {}

    readFn1() {
        readLock.lock();
        /*
             Some Code
        */
        readLock.unlock();
    }

    readFn2() {
        readLock.lock();
        /*
             Some Code
        */
        readLock.unlock();
    }

    writeFn1() {
        writeLock.lock();
        /*
             Some Code
        */
        writeLock.unlock();
    }

    writeFn2() {
        writeLock.lock();
        /*
             Some Code
        */
        writeLock.unlock();
    }
}

该代码似乎工作正常,但我有一些概念性问题。

Q1。我已经看到了在http://en.cppreference.com/w/cpp/thread/shared_mutex/lock上使用unique_lock和shared_lock的建议,但是我不明白为什么这样,因为shared_mutex已经支持lock和lock_shared方法了?

Q2。此代码是否有可能导致写饥饿?如果是,那我该如何避免饥饿呢?

Q3。我可以尝试实现读写锁定的任何其他锁定类吗?

最佳答案

Q1:使用互斥包装

建议使用包装器对象而不是直接管理互斥锁,以避免不幸的情况,在这种情况下,您的代码被中断并且互斥锁未释放,从而使其永远处于锁定状态。

这是RAII的原理。

但这仅在您的ReadLock或WriteLock在使用它的函数本地时才有效。

例子:

readFn1() {
    boost::unique_lock< Lock > rl(lock);
    /*
         Some Code
         ==> imagine exception is thrown
    */
    rl.unlock();   // this is never reached if exception thrown
}  // fortunately local object are destroyed automatically in case
   // an excpetion makes you leave the function prematurely

在您的代码中,如果函数之一被中断,则将无法正常工作,因为您的ReadLock WriteLock对象是Test的成员,而不是局部于设置锁的函数。

Q2:写饥饿

尚不清楚您将如何调用读者和作家,但是是的,存在风险:
  • 只要读取器处于 Activity 状态,写入器就会被unique_lock阻止,以等待互斥体在独占模式下可用。
  • 但是,只要wrtier在等待,新的读取器就可以访问共享锁,从而导致unique_lock进一步延迟。

  • 如果要避免饥饿,则必须确保等待写入的编写者确实有机会设置其unique_lock。例如,在您的读者中输入一些代码来检查作家是否在设置锁之前正在等待。

    Q3其他锁定类

    不太确定您要寻找的内容,但我觉得 condition_variable 可能会让您感兴趣。但是逻辑有些不同。

    也许,您还可以通过开箱即用的思维找到解决方案:也许有一个合适的无锁数据结构,可以通过稍微改变方法来促进读者和作家的共存?

    08-17 15:59