我相信我已经很好地掌握了C ++中多线程的基础知识,但是我从来没有能够在构造函数或析构函数中围绕共享资源锁定互斥锁得到明确的答案。我的印象是你应该锁定这两个地方,但最近同事不同意。假设多个线程访问以下类:
class TestClass
{
public:
TestClass(const float input) :
mMutex(),
mValueOne(1),
mValueTwo("Text")
{
//**Does the mutex need to be locked here?
mValueTwo.Set(input);
mValueOne = mValueTwo.Get();
}
~TestClass()
{
//Lock Here?
}
int GetValueOne() const
{
Lock(mMutex);
return mValueOne;
}
void SetValueOne(const int value)
{
Lock(mMutex);
mValueOne = value;
}
CustomType GetValueTwo() const
{
Lock(mMutex);
return mValueOne;
}
void SetValueTwo(const CustomType type)
{
Lock(mMutex);
mValueTwo = type;
}
private:
Mutex mMutex;
int mValueOne;
CustomType mValueTwo;
};
当然,通过初始化列表,一切都应该是安全的,但构造函数中的语句呢?在析构函数中,执行非作用域锁定是有益的,并且永远不会解锁(基本上只是调用pthread_mutex_destroy)?
答案 0 :(得分:12)
多个线程不能构造相同的对象,也不允许任何线程在完全构造之前使用该对象。因此,在合理的代码中,没有锁定的构造是安全的。
销毁是一个稍微难点的案例。但同样,对象的适当生命周期管理可以确保在某些线程可能仍然使用它时,永远不会销毁对象。
共享指针可以帮助实现这一目标。 :
但显然,存在其他有效方法。关键是要在对象的生命周期的三个主要阶段之间保持适当的界限:构造,使用和破坏。绝不允许任何这些阶段之间重叠。
答案 1 :(得分:1)
它们不必被锁定在构造函数中,因为此时外部任何人都可以访问该数据的唯一方法是从构造函数本身传递它们(或者执行一些未定义的行为,如调用虚方法)。
[编辑:删除了关于析构函数的部分,因为正如评论所说的那样,如果你试图从一个可能已经死的对象访问资源,你会遇到更大的问题]