【发布时间】:2011-07-01 12:10:29
【问题描述】:
使类线程安全的直接方法是添加互斥体属性并在访问器方法中锁定互斥体
class cMyClass {
boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};
问题是这使得类不可复制。
我可以通过将互斥体设为静态来使事情正常进行。但是,这意味着当访问任何其他实例时,该类的每个实例都会阻塞,因为它们都共享相同的互斥体。
不知道有没有更好的办法?
我的结论是没有更好的方法。使用私有静态互斥体属性使类线程安全是“最好的”: - 它简单,有效,并且隐藏了尴尬的细节。
class cMyClass {
static boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};
缺点是类的所有实例共享相同的互斥体,因此不必要地相互阻塞。这无法通过使 mutex 属性为非静态(因此为每个实例赋予其自己的 mutex)来解决,因为如果操作正确,复制和分配的复杂性将是噩梦般的。
如果需要,单个互斥锁必须由外部不可复制单例管理,并在创建时建立到每个实例的链接。
感谢所有回复。
有几个人提到过编写我自己的复制构造函数和赋值运算符。我试过这个。问题是我的真实班级有许多在开发过程中总是在变化的属性。维护复制构造函数和assignmet 运算符既繁琐又容易出错,错误会导致难以发现的错误。让编译器为复杂的类生成这些是巨大的节省时间和减少错误的方法。
许多响应都关心使复制构造函数和赋值运算符线程安全。这个要求给整个事情增加了更多的复杂性!对我来说幸运的是,我不需要它,因为所有的复制都是在设置过程中在一个线程中完成的。
我现在认为最好的方法是构建一个小类来保存互斥锁和关键属性。然后我可以为关键类编写一个小的复制构造函数和赋值运算符,让编译器来处理主类中的所有其他属性。
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();
}
};
【问题讨论】:
-
我曾经尝试过一次,但做得不太好。我想我共享了 boost::mutex (存储了对互斥锁的引用),但我不记得它的效果如何(以及与使其成为静态相同的问题)。我饶有兴趣地等待。
-
互斥体不可复制,所以默认的复制构造函数和赋值操作符不起作用,但为什么不能自己写呢?
-
您确实意识到只有在一个对象被修改的同时它被用来克隆另一个对象时才需要这样做?我会怀疑以这种方式构建的程序是一个问题......
-
@outis:你可以。隐含的问题是如何使赋值运算符和复制构造函数线程安全。然而,这是一个完全不同的故事。
-
@André Caron 也许我应该解释一下我需要做什么。我需要能够将类实例存储在 std::vector 容器中,因此它们必须是可复制的。我还希望能够从多个线程访问类实例的属性。所以这个类必须是可复制的和线程安全的。我不认为需要使复制线程安全:在初始化期间复制仅从一个线程完成。
标签: c++ boost-thread