【问题标题】:Copy Class with std::mutex使用 std::mutex 复制类
【发布时间】:2015-05-20 03:59:04
【问题描述】:

我有一个以 std::mutex 作为成员的类。我正在尝试创建此类类的数组

class C
{
 int x;
 std::mutex m;
};

int main()
{
  C c[10];
  //later trying to create a temp C
  C temp = c[0];
}

显然以上是不可能的,因为互斥对象是不可复制的。解决方法是通过拷贝构造函数。

但是,我在创建复制构造函数时遇到了问题。我试过了

C (const C &c)
{
   x = c.x;

   //1. m
   //2. m()
   //3. m = c.m
}

我不确定这 3 个选项中的正确语法是什么。请帮忙。

【问题讨论】:

标签: c++ c++11


【解决方案1】:

你不应该写任何这些行。您对复制构造函数的实现相当于:

C (const C &c) : x(), m()
{
   x = c.x;
}

所以互斥锁m 的新实例是default initialized,这意味着将调用默认构造函数之一。它可以安全使用。

但是,关于此代码有几个问题。 IE。如果m 保护x,则应在访问值之前显式锁定它:

C (const C &c)
{
    std::lock_guard<std::mutex> (c.m);
    x = c.x;
}

这需要将m 声明为可变(因为c 是复制ctor 中的常量引用)。

mutable std::mutex m;

最后,您可以看到复制带有互斥锁的对象是令人困惑的,如果C 是公共类,它会混淆它的用户,所以在实施复制之前要三思而后行。

【讨论】:

  • 为什么必须在复制构造函数中锁定对x 的写入? C 尚未构造,因此无法在线程之间共享(在复制 ctor 期间)。
  • @user4815162342: c 必须被构造,因为我们正在复制它,即:C a; std::thread([](const C&amp; c) { C tmp = c; c.x = 20; }, c) a.x = 10;。如果没有锁定互斥锁,这是一个竞争条件。
  • 哦,我明白了,您指的是读取c.x,而不是写入this-&gt;x。很抱歉造成混乱。
【解决方案2】:

简短的回答你不要复制互斥体。

让我们从基础开始,互斥锁是互斥的简称,即您要确保,当有多个线程时,您不希望它们并行更改/修改值。您想序列化访问或修改/读取,以使读取的值有效。

在上述情况下,您正在将新值复制到变量中。在这种情况下,您无需使用互斥锁,因为您正在创建新对象。

【讨论】:

  • 另请参阅@myaut 答案以了解如何确保在复制从中复制的对象时有效
  • 那你把互斥锁放在哪里?
【解决方案3】:

您可以使用shared_ptr&lt;C&gt; 的数组,然后您就不需要C 本身是可复制的...

【讨论】:

    【解决方案4】:

    std::mutex m 不必复制。您可以使用默认构造的互斥锁。

    【讨论】:

      【解决方案5】:

      正如其他答案中所述,只有在非常特殊的情况下您想要这样做,但如果您有一些在内部使用互斥锁的对象类,您将需要复制和移动构造函数明确声明要移动和复制的所有内容,但互斥锁除外。这将导致互斥体(以及任何其他遗漏)被默认构造(即每个新的或复制的对象都将获得自己唯一的互斥体)。确保在使用复制或移动构造函数时不会调用任何用于保护的互斥锁,因为它们不会(不能?)调用互斥锁来锁定。

      这是一个完整的示例,可以帮助将来遇到此问题的任何人:

      class Shape
      {
      public:
          Shape() {} //default constructor
          Shape(double _size) //overloaded constructor
          {
              size = _size;
          }
      
          Shape(const Shape& obj) //copy constructor (must be explicitly declared if class has non-copyable member)
          {
              //Do not put any non-copyable member variables in here (ie the mutex), as they will be
              //default initialized if left out
      
              size = obj.size; //any variables you want to retain in the copy
          }
          Shape& operator=(const Shape&& obj) //move constructor (must be explicitly declared if class has non-copyable member)
          {
              //Do not put any non-copyable member variables in here (ie the mutex), as they will be
              //default initialized if left out
      
              size = obj.size;//any variables you want to retain in the move
              return *this;
          }
      
          double testMe() { return size; }
      private:
          std::mutex dataMutex;
          double size;
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-03-28
        • 2016-04-23
        • 2013-12-29
        • 2012-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多