在使用 boost 共享互斥锁时,我应该在啥情况下使用 owns_lock() 函数

Posted

技术标签:

【中文标题】在使用 boost 共享互斥锁时,我应该在啥情况下使用 owns_lock() 函数【英文标题】:In what circumstances should I use owns_lock() function when working with boost shared mutexes在使用 boost 共享互斥锁时,我应该在什么情况下使用 owns_lock() 函数 【发布时间】:2017-06-14 21:02:50 【问题描述】:

我正在使用 C++ 多线程程序,该程序必须使用 boost shared_mutex 在类中读取和写入一些属性。该程序在执行时会创建一个类 A 的多个对象实例。此类 A 有一个静态 shared_mutex ,由所有 A 类对象共享。如果该类的属性之一需要写入其中一个对象实例,则特定对象实例需要通过将共享互斥锁升级为唯一锁来获得对共享互斥锁的独占访问权。但是,在此之前,set 方法会检查类实例是否拥有锁,这对我来说有点奇怪。

这或多或少是 A 类 hpp 文件的样子:

#include <boost/thread.hpp>

class A
    private:
        //Private methods
        void setAttribute(boost::upgrade_lock<boost::shared_mutex>& lock, const bool value);
        //Private variables
        static boost::shared_mutex mainMutex;
        mutable bool attribute;
    public:
        //... Some public methods using setAttribute

这就是 A 类 cpp 文件的样子:

void A::setAttribute(boost::upgrade_lock<boost::shared_mutex>& lock, const bool value)

    (void)lock;
    assert(lock.owns_lock());

    //get exclusive access to the lock
    const boost::upgrade_to_unique_lock<boost::shared_mutex> ulock(lock);
    attribute = value;

所以,我的问题是为什么我需要检查传递的锁是否拥有锁,因为 setAttribute 方法是私有的并且它只被类中的方法使用。在任何情况下我应该考虑这样做吗?

【问题讨论】:

(void)lock; 那是什么? 从我看到的关于如何使用 shared_mutex 的示例中,他们总是调用 lock() 然后升级到唯一锁以获得独占访问。因此,'(void) lock' 似乎调用了一个重载运算符,该运算符为 upgrade_lock 调用 lock() 函数?但是,我不能 100% 确定这一点,因为我无法通过我迄今为止所做的研究来证实这一点 “从我见过的例子” - 链接? 这是我看到的关于如何使用 shared_mutex 的示例之一:link。当一个线程尝试写入时,它们首先创建一个以共享互斥锁作为输入的 upgrade_lock,然后使用 upgrade_to_unique_lock 获得独占访问。这里 upgrade_lock 作为参考传递,所以我想也许 (void) lock 正在做实例化或一些副作用,它需要获得可升级的访问权限 然后发个链接!!! 【参考方案1】:

(void) lock; 条件存在于此,以避免在编译期间使用类似g++ -DNDEBUG -Wall -Werror -pedantic 的内容时出现编译错误。这指示编译器停止对未使用变量(除其他外)的所有警告。当程序员不知道变量是否会被使用但又不想破坏构建时,有时会在代码中使用这种技术。

owns_lock() 方法表示特定对象已获得锁的所有权。或者换个说法,锁定对象。如果它是一个共享锁,那么多个对象可以“拥有”它。 “拥有”是“被此对象锁定”的同义词。如果它是唯一的锁,那么只有一个对象可以拥有它。

assert() 可能只是用于调试构建,如果没有它,代码将无法尝试悄悄地将锁升级为唯一锁;即使锁不属于线程(例如,它已解锁)。如果这是真的,那么升级将静默失败。

例如,如果在禁用assert 的情况下发生如下操作顺序,则代码将静默失败:

boost::upgrade_lock<boost::shared_mutex> lock(this->mainMutex);
lock.unlock();
this->setAttribute(lock, false);

upgrade_lock 调用获取锁的升级所有权。这意味着有一个合同说这个对象可以升级锁。

upgrade_to_unique_lock 调用通过停止直到任何其他共享所有者释放锁来将共享锁实际升级为唯一锁。如果在调用 this 时该锁不属于该对象,那么它将无提示地将锁升级为唯一锁。

TLDR;我怀疑作者的意图是让互斥代码对类保持私有,但想要放置一个断言,以防在 setattribute() 之前的某个地方意外调用了 unlock()。

【讨论】:

以上是关于在使用 boost 共享互斥锁时,我应该在啥情况下使用 owns_lock() 函数的主要内容,如果未能解决你的问题,请参考以下文章

悲观锁和乐观锁

悲观锁和乐观锁

两个线程都在调用 boost::mutex::lock() 时阻塞

在啥情况下我应该使用尝试而不是二叉树/哈希表? [复制]

.NET 进程和 AppDomain 在啥情况下会共享内存中加载的程序集?

在啥情况下你应该更喜欢使用 std::copy 写入 cout?