C++ 无主互斥锁的解锁

C++ 无主互斥锁的解锁,c++,C++,我创建了以下类,它提供了一个acquire\u lock()和release\u lock()函数 class LockableObject { public: void acquire_lock() { std::unique_lock<std::mutex> local_lock(m_mutex); m_lock = std::move(local_lock); } void release_lock() {

我创建了以下类,它提供了一个
acquire\u lock()
release\u lock()
函数

class LockableObject {

public:

    void acquire_lock() {
        std::unique_lock<std::mutex> local_lock(m_mutex);
        m_lock = std::move(local_lock);
    }

    void release_lock() {
        m_lock.unlock();
    }

private:

    std::mutex m_mutex;

    std::unique_lock<std::mutex> m_lock;
};
acquire_lock
函数中,我首先尝试通过在构造函数中传递它(
m_mutex
),用本地堆栈
std::unique_lock
对象锁定底层互斥体(
m_mutex
)。我假设
std::unique\u lock
的构造函数返回它已锁定互斥锁后,我将堆栈上的
unique\u lock
移动到成员变量
m\u lock


这个程序在一些基本方面有缺陷,在调用
释放锁
的过程中,会导致
“无主互斥锁的解锁”
,我似乎缺少了一些关于
std::unique\u lock
的基本信息,我正在找人纠正我的理解

请参阅我关于构造函数中缺少
std::defer\u lock
的评论。但代码中也有一个竞争条件

acquire_lock
功能在
m_互斥锁
的保护下修改
m_锁
。因此,为了确保线程安全,除了持有
m_互斥锁
外,其他线程都不能修改
m_锁

但是
release\u lock
函数在释放互斥锁时修改
m\u lock
。因此,在
m_lock
上没有正确的同步

这有点难以理解。这是问题代码:

    m_lock.unlock();
请注意,当输入此函数时,
m_mutex
被锁定,但在其执行过程中,它会修改
m_lock
并释放
m_mutex
,没有特定的保证顺序。但是
m_互斥锁
保护
m_锁
。所以这是比赛条件,是不允许的

它可以按如下方式固定:

void release_lock() {
    std::unique_lock<std::mutex> local_lock = std::move(m_lock);
    local_lock.unlock();
}
void release\u lock(){
std::unique_lock local_lock=std::move(m_lock);
本地_lock.unlock();
}
现在,这第一行代码修改
m_lock
,但完全在
m_mutex
保持的情况下运行。这避免了竞争条件

如果需要,可以移除
解锁
local\u lock
的析构函数将执行此操作


顺便说一下,我建议更改API。与其提供锁定和解锁调用,不如使用一种方法创建一个拥有此对象锁的对象。如果需要,您甚至可以使用
std::unique_lock
。为什么要创建一个比标准提供的API更差的新API?

可以按如下方式更改成员函数
acquire\u lock
,以解决此问题:

void acquire_lock() {
    m_lock = std::unique_lock<std::mutex>(m_mutex);
}
void acquire_lock(){
m_lock=std::唯一的_锁(m_互斥锁);
}

将调用
unique\u lock
的函数来管理
m\u lock

中的mutex对象
m\u mutex
std::defer\u lock
的构造函数,因此在构造它时它已经被锁定。然后尝试锁定它,这将抛出一个
std::system\u错误
。你确定这是代码吗?m_lock=std::unique_lock(m_mutex);而不是std::move@DavidSchwartz你是对的,我在问题中错误地复制了一些代码。我已经纠正了代码现在删除调用锁定后,建设,现在这将失败,只有在解锁。或者,我也尝试在构造local_lock时使用std::defer_lock作为第二个参数调用构造函数,然后显式调用local_lock上的lock()方法,但该行为保持不变,它运行了几次迭代,然后在“unowned mutex解锁”时出错@arunsun请参见下面的答案。你也有比赛条件。我相信这只是一个输入错误。@David Hastoff,谢谢你的帮助,这确实是比赛条件,我仍在尝试探索这里的确切细节,但我很惊讶这两个操作是如何准确地理解这场比赛的-查看std_互斥中解锁的实现。h我看到这个函数首先在_M_设备上调用解锁,然后将_M_owns设置为false,假设现在一个线程是解锁代码,恰好在_M_设备上调用了解锁,但还没有将_M_owns设置为false,此时另一个线程锁定,然后在第二个线程调用解锁之前,第一个线程现在将_M_owns设置为false,导致第二个线程出错。我还花了一些时间考虑您关于更改API的建议,您可能会认为API不吸引人,但是当我想到它时,我有以下思考过程,我有一个由多个线程处理的共享对象的集合,在我的心智模型中,我发现锁信息存在于这些被锁定的对象中是很方便的,这样可以避免额外查找与被锁定对象关联的中央锁对象。有什么更好的建议吗?@arunsun我认为这不是一个很有帮助的思考方式。考虑这个问题的方法很简单,如果没有同步,您不能在多个线程中访问对象。按照你建议的方式思考会导致错误的想法,即当你认为它不可能失败时,这意味着它不会失败。在这种情况下,你可以想出一种失败的方法,但即使你不能,也不意味着它不能失败。我相信另一个答案是正确的,问题似乎发生在release_lock()函数中,不过,我非常感谢您对acquire_lock功能的更新,该功能似乎相当于我的acquire_lock,但只有一行而不是两行。
void acquire_lock() {
    m_lock = std::unique_lock<std::mutex>(m_mutex);
}