在C++11中将读锁升级为写锁而不释放第一个锁?

5

我知道在C++14中可以使用boost::UpgradeLockable实现此功能。

那么在C++11中是否有类似的方法呢?


1
不幸的是,直到C++17才支持:http://en.cppreference.com/w/cpp/thread/shared_mutex - Richard Hodges
@RichardHodges 我不明白那个链接与此相关。在该界面的哪里可以允许锁升级? - Yakk - Adam Nevraumont
@Yakk 嗯,你是对的。那么问题来了,标准提案是缺少什么,还是可升级锁根本不必要? - Richard Hodges
如果客户端代码能够像在std中一样高效地完成任务,那么我们是否应该将其放入std中?也许可以考虑。 - Yakk - Adam Nevraumont
我不明白你的问题。如果你要使用Boost.Threads,那么为什么需要C++14?Boost.Threads已经有可升级的shared_mutex很多年了,并且只需要C++98。 - Arne Vogel
1个回答

2

可升级锁可以在更简单的锁原语之上编写。

struct upgradeable_timed_mutex {
  void lock() {
    upgradable_lock();
    upgrade_lock();
  }
  void unlock() {
    upgrade_unlock();
    upgradable_unlock();
  }
  void shared_lock() { shared.shared_lock(); }
  void shared_unlock() { shared.shared_unlock(); }

  void upgradable_lock() { unshared.lock(); }
  void ungradable_unlock() { unshared.unlock(); }

  void upgrade_lock() { shared.lock(); }
  void upgrade_unlock() { shared.unlock(); }
private:
  friend struct upgradable_lock;
  std::shared_timed_mutex shared;
  std::timed_mutex unshared;
};

对于定时和尝试变体,类似的操作。请注意,连续访问两个互斥锁的定时变体必须进行一些额外的工作,以避免花费多达2倍所请求的时间,并且try_lock必须小心第一个锁的状态,以防第二个失败。

然后,您需要编写upgradable_lock,并能够根据需要生成std::unique_lock

自然而然地,这是手写的线程安全代码,因此可能不正确。

在C++1z中,您还可以编写无定时版本(使用std::shared_mutexstd::mutex)。


不太具体地说,一次只能有一个可升级或写锁。这就是unshared互斥锁所代表的。

只要持有unshared,没有其他人会写入受保护的数据,因此您可以在根本不持有共享互斥锁的情况下从中读取。

当您想要升级时,可以在共享互斥锁上获取唯一锁。只要没有读者尝试升级到可升级状态,这样做就不会死锁。这将排除读者的阅读,您可以编写,然后释放它并返回到只读状态(在此状态下,您仅持有未共享的互斥锁)。


这个解决方案需要在升级时放弃shared互斥锁的shared_lock,然后寻求一个唯一的互斥锁。这种情况下,第二个互斥锁unshared将是多余的,或者我漏掉了什么? - Richard Hodges
1
@RichardHodges 可升级的锁根本不拥有共享锁。它只在非共享互斥量上拥有一个 unique_lock。当进行升级时,它直接在共享互斥量上获取一个 unique_lock。这样做的目的是在升级时不会失去读锁。 - Yakk - Adam Nevraumont

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接