【问题标题】:C++ operator= with a mutex in class memberC++ operator= 在类成员中具有互斥锁
【发布时间】:2014-09-19 19:20:37
【问题描述】:

我有一个包含一些变量的类,比如一个列表和一个布尔值,可以由多个线程写入,因此使用它们自己的互斥锁进行保护:

class Motel
{
// [...]
private:
    list<Room> _rooms;
    boost::mutex _rooms_mtx;
    bool _opened;
    boost::mutex _opened_mtx;
}

这段代码的问题是当我需要一个复制构造函数或 operator=(甚至是自动生成的)时,我想将类放在地图中:

boost::map<string, Motel> all_motels;
Motel grenoble(...);
all_motels["Grenoble"] = grenoble;

这是禁止的,因为我们不能复制互斥锁:

/usr/include/boost/thread/pthread/mutex.hpp: In copy constructor ‘project::Motel::Motel(const project::Motel&)’:
/usr/include/boost/thread/pthread/mutex.hpp:33:9: error: ‘boost::mutex::mutex(const boost::mutex&)’ is private

在这种情况下我该怎么办? 提前谢谢你

【问题讨论】:

标签: c++ thread-safety mutex member


【解决方案1】:

这里的常见解决方案是使Motel 不可复制,并且Motel 对象在堆上分配new。使用boost::noncopyable 和智能指针也是一个好主意。

class Motel : private boost::noncopyable
{
// [...]
private:
    list<Room> _rooms;
    boost::mutex _rooms_mtx;
    bool _opened;
    boost::mutex _opened_mtx;
}

boost::map<string, boost::unique_ptr<Motel> > all_motels;
all_motels["Grenoble"].reset(new Motel(...));

【讨论】:

  • 谢谢大家。指针是如此明显,我什至没有想到他们。我现在使用 shared_ptr 的映射和不可复制的类。
【解决方案2】:

您无法复制 boost::mutex (您的错误消息显示 boost 阻止了它,但尝试复制互斥锁是蠕虫的巢穴)。至少您必须为Motel 编写自己的复制构造函数,并且您必须弄清楚如何处理互斥锁。您很可能想自己创建一个互斥锁。

【讨论】:

    【解决方案3】:

    另一种解决方案是使用互斥指针。

    private:
        list<Room> _rooms;
        boost::mutex* _rooms_mtx;
        bool _opened;
        boost::mutex* _opened_mtx;
    }
    

    顺便说一句,您必须确保尊重这些问题:

    • 是否会正确创建互斥锁?
    • 能否正确使用互斥锁?

    【讨论】:

      【解决方案4】:

      您必须提供一个复制构造函数和一个赋值重载(operator=),它们不是复制互斥体而是复制数据。见this运行示例:

      #include <map>
      #include <boost/thread/mutex.hpp>
      
      
      class foo {
      public:
          foo() {}
          foo(foo const& cp)
              : data_(cp.data_) {}
      
          foo& operator=(foo const& cp) {
              data_ = cp.data_;
              return *this;
          }
      
      private:
          boost::mutex mtx_;
      
          bool data_;
      };
      
      
      int main(int argc, char* argv[]) {
          std::map<int, foo> bar;
          bar[1] = foo();
          return 0;
      }
      

      但是

      互斥体用于共享对象,这不是通过复制它们来完成的。所以通常希望不能复制它们。因此,您应该使用 shared_ptr(std (c++11)boost)。然后你使用 shared_ptr 的映射:

      int main(int argc, char* argv[]) {
          std::map<int, std::shared_ptr<foo>> bar; // untested but you see the point
          bar[1] = std::shared_ptr<foo>(new foo); 
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2011-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多