【问题标题】:Upgrade shared_lock to unique lock usage, timing and design将 shared_lock 升级为独特的锁使用、时序和设计
【发布时间】:2020-04-29 19:36:13
【问题描述】:

我正在更新以前使用自己的读写锁机制的代码(此代码是在 C++11 之前编写的,并且 std::shared_mutex 尚不存在) 使用标准版本的 C++。

有两个类叫做ReadLock和WriteLock,ReadLock可以通过方法调用升级为WriteLock。 WriteLock 也可以随时获取,无需从 shared_lock 升级。 阅读 shared_lock 的 C++ 标准版本,我认为它简单明了。

ReadLock 将被 shared_lock 替换 WriteLock 将替换为 unique_lock 并且可以在任何时候调用 lock() 来触发以获取 Writelock 升级到 Writelock 只需两步 解锁 shared_lock 和锁定 unique_lock

我现在的问题是,当我通过讨论阅读时,可能存在特定问题,并且像这样的线程引起了关注(来自 Howard Hinnant 的线程) Can a shared lock on a std::shared_timed_mutex be upgraded to an exclusive lock?

所以我考虑改用 boost 版本,因为它支持 upgrade_lock 和 boost::upgrade_to_unique_lock,但我对如何处理它的设计感到困惑。

WriteLock 类既可以表示 unique_lock 和/或 upgrade_lock 和 upgrade_to_unique_lock 对象,因为如上所述,WriteLock 也可以在没有 shared_lock 的情况下实现。

另外,如果我使用 boost 中的 upgrade_lock,我对如何显式触发 lock() 和 unlock() 机制感到困惑; boost::upgrade_lock 有一个构造函数,它接受 defer_lock 作为参数,并具有我可以随时使用的 lock() 和 unlock() 方法,但是如果我们使用 boost::upgrade_to_unique_lock() 将其升级为唯一锁,我看不到相同的功能,创建 upgrade_to_unique_lock() 的对象会自动转换并锁定它。

这是我想要达到的伪代码 方法一基本操作

    void foo()
    {
        ReadLock readLock = someWrapper->AcquireReader();    // return a shared lock
        ...
        WriteLock writeLock = readLock->UpgradeToWriter();   // returns a unique lock
        writeLock->Lock();
        // do something here
    }   // writelock are unlock since constructor is called

方法 2 直接写锁

    void foo()
    {
        WriteLock writeLock = someWrapper->GetWriter();   // acquire lock straight
        writeLock->Lock();
        // do something here
    }   // writelock are unlock since constructor is called
}

所以我的问题是

  1. 如果我使用 std C++ 是否有效,我需要使用 boost 来代替,或者 C++ std::shared_mutex 是否足够? 在上面的示例中,UpgradeToWriter() 和 GetWriter() 都只会返回一个带有 unique_lock 的对象,但 Upgrade 只会首先解锁 shared_lock。
  2. 如果我使用 boost 版本,我应该如何处理设计,因为 upgrade_to_unique_lock 与 unique_lock 的类型不同? 我在想 WriteLock 类都包含 unique_lock、upgrade_lock 和 boost:upgrade_to_unique_lock 的定义,并且无论是升级还是简单的获取都会被锁定,这让我想到了我的最后一个也是最后一个问题
  3. 如何显式或延迟/触发 boost:upgrade_to_unique_lock 的锁定?因为它没有 defer_lock 参数,也没有 lock() 和 unlock() 方法,只有构造函数来做他的事情?

来自 boost::upgrade_to_unique_lock 用法的 boost 示例,所有示例都类似于以下代码,自动创建对象会触发转换和锁定。

void writer()
{
  // get upgradable access
  boost::upgrade_lock<boost::shared_mutex> lock(_access);

  // get exclusive access
  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock); // <-- want this to be performed or triggered explicitly, how?
  // now we have exclusive access
}

先谢谢你了,我知道这里有C++高手可以帮助兄弟们

【问题讨论】:

  • 如果两个读卡器同时尝试升级他们的锁,你想发生什么?或者你想要一个特殊的“不可分级锁”,一次只能有一个读者拥有?
  • Sane 库升级有 3 个锁:读、升级和写。最多可以存在一个(上/写)。一个 up 可以存在任意数量的读取。升级到写入会阻塞所有新的读取器并等待现有读取器完成,然后变成写入锁。 OP手写的系统似乎没有这样做?看来 boost 确实如此。这是你的问题吗,OP?
  • @DavidSchwartz writer lock 应该是独占的,所以如果两者都尝试升级,只有一个应该通过。我仍然希望多个读者使用 shared_lock,如果是时候切换到唯一锁,我可能不得不使用 upgrade_lock,仅此而已。我没有看到“可升级锁”的使用,如果以后不升级为独占,则只允许一个读取器,此时我不太了解只有一个读取器的升级锁的用例,请帮帮我?
  • @user2300947 如果写锁是独占的而另一个持有读锁,如何通过?请参阅我的“答案”,这并不是真正的答案。

标签: c++ multithreading c++11 boost boost-thread


【解决方案1】:

这是你所缺少的:

  1. 两个线程各有一个可升级的读锁。
  2. 两个线程都尝试将其读锁升级为写锁。
  3. 在释放所有其他读取锁之前,两个线程都不能向前推进。
  4. 两个线程都持有一个读锁。

这是一个僵局。所以你有两个选择:

  1. 确保这种情况永远不会发生:一次只有一个线程可以持有可升级的读锁。
  2. 打破死锁:当您尝试升级读锁时,结果可能是操作失败并要求线程在尝试获取写锁之前释放读锁。

【讨论】:

  • 谢谢,我还阅读了open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3427.html,现在了解 update_lock 的理由,如果我使用 boost,我现在的另一个问题是如何通过 boost::upgrade_to_unique_lock 显式触发转换为唯一锁我在网上看到的示例和代码在本地声明它并自动锁定在该范围内。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-11
  • 2011-01-25
  • 1970-01-01
  • 1970-01-01
  • 2011-05-02
相关资源
最近更新 更多