Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在C+;中添加互斥后在结构中的赋值运算符+;_C++_C++11_Struct_Mutex_Assignment Operator - Fatal编程技术网

C++ 在C+;中添加互斥后在结构中的赋值运算符+;

C++ 在C+;中添加互斥后在结构中的赋值运算符+;,c++,c++11,struct,mutex,assignment-operator,C++,C++11,Struct,Mutex,Assignment Operator,我有一个结构类型: struct MyStruct { int field1; int field2; } 然后,有必要向其添加互斥体,以使其在线程之间共享: struct MyStruct { std::mutex _mutex; int field1; int field2; } 但是编译器(clang)在我将一个现有结构赋值给MyStruct类型的变量的行上给我这些消息,比如MyStruct MyStruct=p_MyStructMap->at

我有一个结构类型:

struct MyStruct {
    int field1;
    int field2;
}
然后,有必要向其添加互斥体,以使其在线程之间共享:

struct MyStruct {
    std::mutex _mutex;

    int field1;
    int field2;
}
但是编译器(clang)在我将一个现有结构赋值给MyStruct类型的变量的行上给我这些消息,比如
MyStruct MyStruct=p_MyStructMap->at(clientId)

(1) 错误:“MyStruct”类型的对象无法分配,因为其复制分配运算符已被隐式删除

(2) 注意:“MyStruct”的复制分配运算符被隐式删除,因为字段“\u mutex”有一个已删除的复制分配运算符

std::mutex _mutex
           ^     
(3) /usr/bin/./lib/gcc/x86_64-linux-gnu/4.8/../../../../../../../../include/c++/4.8/mutex:129:12:注意:函数已在此处明确标记为删除

mutex& operator=(const mutex&) = delete;
       ^

请提供帮助:如何重写结构或程序逻辑以使用此结构的互斥体?

std::无法分配互斥体变量/成员,因此,您会遇到错误

试着这样做:

struct MyStruct {
    std::mutex _mutex;

    int field1;
    int field2;

   MyStruct &operator=(const MyStruct &o) {
      field1=o.field1;
      field2=o.field2;
      return *this;
   }
};
MyStruct& operator=(const MyStruct& o)
{
    if (this != &o)
    {
        std::lock(_mutex, o._mutex);
        std::lock_guard<std::mutex> lhs_lk(_mutex, std::adopt_lock);
        std::lock_guard<std::mutex> rhs_lk(o._mutex, std::adopt_lock);
        field1 = o.field1;
        field2 = o.field2;
    }
    return *this;
}

但是,这不会在分配期间锁定互斥锁。根据上下文的不同,您可能需要在赋值运算符或调用函数中添加锁定。

假设添加了
\u互斥体
,以保护其他字段不被同时访问,您将需要在赋值期间锁定互斥体,除非您可以保证多个线程不会访问赋值表达式的任一侧,否则:

x=y

如果任何其他线程同时读取或写入
x
,则有一个未锁定的争用

如果任何其他线程同时写入
y
,则您有一个未锁定的争用

如果您确实需要锁定,它并不像锁定两侧那么简单:

MyStruct& operator=(const MyStruct& o)
{
    if (this != &o)
    {
        // WRONG!  DO NOT DO THIS!!!
        std::lock_guard<std::mutex> lhs_lk(_mutex);
        std::lock_guard<std::mutex> rhs_lk(o._mutex);
        field1 = o.field1;
        field2 = o.field2;
    }
    return *this;
}
线程B同时执行以下操作:

x = y;
y = x;
现在有可能出现死锁。假设线程A锁定x.\U互斥锁,然后线程B锁定y.\U互斥锁。现在,线程A和线程B都将阻止尝试锁定它们的
o.\u互斥锁
,并且两个线程都不会成功,因为它正在等待另一个线程释放它

赋值运算符的正确公式如下所示:

struct MyStruct {
    std::mutex _mutex;

    int field1;
    int field2;

   MyStruct &operator=(const MyStruct &o) {
      field1=o.field1;
      field2=o.field2;
      return *this;
   }
};
MyStruct& operator=(const MyStruct& o)
{
    if (this != &o)
    {
        std::lock(_mutex, o._mutex);
        std::lock_guard<std::mutex> lhs_lk(_mutex, std::adopt_lock);
        std::lock_guard<std::mutex> rhs_lk(o._mutex, std::adopt_lock);
        field1 = o.field1;
        field2 = o.field2;
    }
    return *this;
}
这与以前类似,只是我们需要更改互斥锁的类型,现在lhs使用
唯一锁
(写入锁定lhs互斥锁)锁定,rhs使用
共享锁
(读取锁定rhs互斥锁)。这里我们还使用
std::defer_lock
来构造锁,但告诉锁互斥锁尚未锁定,并且不锁定构造。然后我们的老朋友
std::lock(m1,m2)
被用来告诉两个锁同时锁定,而不会出现死锁。是的,
std::lock
同时适用于互斥和锁类型。任何具有成员
lock()
try_lock()
unlock()
的内容都将使用
std::lock(m1,m2,…)

注意,C++14技术并不一定是一种优化。你必须测量以确认或否认这一点。对于像
MyStruct
这样简单的东西,除了一些特殊的使用模式之外,它可能不是一种优化。带有std::mutex的C++11技术仍然是工具箱中的一个有价值的工具,即使在C++14中也是如此

为了便于在
互斥体
共享_timed_mutex
之间切换回第四个互斥体和第四个互斥体,此最新示例使用了类型别名,可以轻松更改。只需更改两行即可切换回互斥体:

#include <mutex>
#include <shared_mutex>

struct MyStruct
{
    using MutexType = std::shared_timed_mutex;
    using ReadLock = std::shared_lock<MutexType>;
    using WriteLock = std::unique_lock<MutexType>;

    mutable MutexType _mutex;

    int field1;
    int field2;

    MyStruct& operator=(const MyStruct& o)
    {
        if (this != &o)
        {
            WriteLock lhs_lk(_mutex, std::defer_lock);
            ReadLock  rhs_lk(o._mutex, std::defer_lock);
            std::lock(lhs_lk, rhs_lk);
            field1 = o.field1;
            field2 = o.field2;
        }
        return *this;
    }

};
使用MutexType=std::
shared\u timed\ucode>mutex

使用ReadLock=std::
共享
唯一锁


使用WriteLock=std::unique_lock

您可以定义自己的赋值运算符,它不会影响互斥(除了锁定之外)。很可能您想要
MyStruct&MyStruct=p\u MyStructMap->at(clientId)感谢您的详细回答,但是,我遇到了std::lock(_mutex,o._mutex)的问题,我得到错误“传递…
'this'
参数丢弃限定符”。我已经把它缩小到
o._mutex
作为罪魁祸首,这很有道理b/c
o
const
,当然
std::lock
想要修改
o
的mutex。给出的答案是否有缺陷,或者我遗漏了一些简单的东西?不幸的是,我目前只使用c++11。当然,如果有必要的话,我可以问一个新问题。让您的数据成员互斥
可变。