设计一个线程安全的可复制类

rav*_*int 9 c++ boost-thread

使类线程安全的直接方法是添加互斥锁属性并在访问器方法中锁定互斥锁

class cMyClass {
  boost::mutex myMutex;
  cSomeClass A;
public:
  cSomeClass getA() {
    boost::mutex::scoped_lock lock( myMutex );
    return A;
  }
};
Run Code Online (Sandbox Code Playgroud)

问题是这使得该类不可复制.

我可以通过使互斥锁成为静态来使事情发挥作用.但是,这意味着当访问任何其他实例时,类的每个实例都会阻塞,因为它们都共享相同的互斥锁.

我想知道是否有更好的方法?

我的结论是没有更好的方法.使用私有静态互斥锁属性创建一个线程安全的类是"最好的": - 它很简单,它有效,它隐藏了尴尬的细节.

class cMyClass {
  static boost::mutex myMutex;
  cSomeClass A;
public:
  cSomeClass getA() {
    boost::mutex::scoped_lock lock( myMutex );
    return A;
  }
};
Run Code Online (Sandbox Code Playgroud)

缺点是类的所有实例共享相同的互斥锁,因此不必要地相互阻塞.这不能通过使互斥属性非静态(因此为每个实例赋予其自己的互斥锁)来解决,因为如果正确完成,复制和赋值的复杂性是噩梦般的.

如果需要,各个互斥锁必须由外部不可复制的单例管理,并在创建时为每个实例建立链接.


感谢所有的回复.

有几个人提到编写我自己的复制构造函数和赋值运算符.我试过这个.问题是我的真正的类具有许多在开发期间总是在变化的属性.维护复制构造函数和assignmet运算符是繁琐且容易出错的,错误导致难以发现错误.让编译器为复杂类生成这些是一个巨大的节省时间和bug减少器.


许多响应都关注使复制构造函数和赋值运算符是线程安全的.这个要求为整个事情增加了更多的复杂性!幸运的是,我不需要它,因为所有复制都是在单个线程中进行设置时完成的.


我现在认为最好的方法是构建一个小类来保存互斥锁和关键属性.然后我可以为关键类编写一个小的复制构造函数和赋值运算符,并让编译器来管理主类中的所有其他属性.

class cSafe {
  boost::mutex myMutex;
  cSomeClass A;
public:
  cSomeClass getA() {
    boost::mutex::scoped_lock lock( myMutex );
    return A;
  }
  (copy constructor)
  (assignment op )

};
class cMyClass {
  cSafe S;
  ( ... other attributes ... )
public:
  cSomeClass getA() {
    return S.getA();
  }
};
Run Code Online (Sandbox Code Playgroud)

Pup*_*ppy 4

简单的事实是,您不能通过在问题上喷出互斥体来使类线程安全。你无法做到这一点的原因是因为它不起作用,而不是因为你使用了错误的技术。这是当多线程刚出现并开始屠杀 COW 字符串实现时每个人都注意到的。

线程设计发生在应用程序级别,而不是基于每个类。只有特定的资源管理类应该在此级别上具有线程安全性,并且对于它们,您无论如何都需要编写显式的复制构造函数/赋值运算符。