首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有重复参数的Scoped_lock

问带有重复参数的Scoped_lock
EN

Stack Overflow用户
提问于 2021-05-02 12:21:59
回答 1查看 233关注 0票数 6

在多线程环境中,我使用std::scoped_lock来保护对对象.但我发现,如果scoped_lock的参数是相同的,则会导致死锁(在Visual和gcc中)。例如,

代码语言:javascript
复制
#include <mutex>

struct S
{
    mutable std::mutex m;
    int v = 0;
    S & operator = ( const S & b )
    {
        std::scoped_lock l( m, b.m );
        v = b.v;
        return * this;
    }
};

int main()
{
    S a;
    a = a; //deadlock here!
}

我看到该标准要求“如果MutexTypes中的一个不是递归互斥,并且当前线程已经在.中拥有相应的参数,则行为是未定义的”,请参见https://en.cppreference.com/w/cpp/thread/scoped_lock/scoped_lock

但在我的示例中,互斥锁在scoped_locked之前并没有被正式锁定。那么它是预期的程序行为吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-02 15:14:50

您真正害怕的现象是“自死锁”。当同时满足两个条件时,就会发生这种情况:

  • 相同的线程在同一个互斥对象(

H 111)上反复调用mutex.lock(),该互斥对象属于非递归类型,不支持这种递归锁定。H 212f 213

在C++中,有两种类型的互斥:

  • std::mutex是非递归类型-它更快,需要更少的资源,
  • std::recursive_mutex是递归类型-它更安全,但需要更多的资源。

现在,让我们将这些知识应用于您的具体示例:

  1. 在您的例子中,避免“自死锁”的明显方法是避免“自赋值”。为此,只需添加附加检查:

S& operator =( const &b) { if (this =&b) //检查它不是自赋值{ std::scoped_lock l( m,b.m );v= b.v;}返回* this;}

如果这是您的互斥锁( mutex )的唯一用法,则可以确保递归的“自死锁”永远不会发生。因此,这是最好和最便宜的解决方案。

如果要添加其他“同步”方法(在调用线程已经持有互斥对象时调用当前方法),那么(仅在这种情况下)您确实需要替换std::recursive_mutex.的std:: mutex 类型。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67356331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档