这很可怕吗?可复制的互斥锁以保护类成员

时间:2013-11-21 16:50:43

标签: c++ multithreading

我正在尝试使用互斥锁使类线程安全。

class Container
{
  private:
   vector<Foo> v;
   boost::mutex m;
  public:
   void add(Foo item)
   {
      m.lock();
      v.push_back(item);
      m.unlock();
   }
};

问题是boost::mutex是不可复制的,因此这使得Container不可复制。当然,如果我复制Container,新实例可能不需要保留与旧实例相同的互斥锁 - 它可以拥有自己的新互斥锁。我可以为Container编写自定义复制构造函数,但实际上它是一个复杂的类,我不想这样做。那怎么样:

class CopyableMutex
{
private:
    boost::mutex m;
public:
    CopyableMutex() {}
    CopyableMutex(CopyableMutex&) {} //don't copy, just create a new one
    CopyableMutex& operator=(CopyableMutex&) {return *this;} //don't assign, keep it the same
    void lock() {m.lock();}
    void unlock() {m.unlock();}
};

...然后将boost::mutex中的Container替换为CopyableMutex

这是一件可怕的事吗?如果没有,那么我是否重新发明轮子 - 是否有一个库类已经这样做了?

2 个答案:

答案 0 :(得分:2)

是的,这很可怕。

问题的正确解决方案是容器的自定义复制构造函数和赋值运算符。

如果类太“复杂”而无法编写自定义复制构造函数,那么将线程安全与容器分开,并使基类容器不包含互斥锁,也许还有派生类“线程安全”容器“包含一个互斥锁,并且有一个自定义复制构造函数和赋值操作,只调用自动生成的基类。

答案 1 :(得分:0)

我相信,以这种方式无效的事情之一就是如今使用互斥体的正确方法:

void func()
  {
    std::lock_guard<std::mutex> lock(mtx);
    // do things
  }

由于您无法返回互斥锁,因此无法将其扩大到您要使用的位置。使用上述样式的原因是为了防止在使用锁时出现问题,然后在解锁之前发生某种形式的未处理异常(即,它确保了更可靠的解锁)。

不过,我同意其他答案,更好的方法是封装线程安全部分并将其与复杂代码隔离(如果可能),然后为该较小的类创建显式的副本构造函数。