Mutex作为类成员

10
 class temp
 {
    boost::mutex mx;
    void CriticalCode() {
        boost::mutex::scoped_lock scoped_lock(mx); 
        //Do Something
        return;
    }
 }
  1. 如果这个类被分配在堆上 (temp* T = new temp()),那么每个实例都是线程安全的吗?

  2. 如果我把 boost::mutex mx 变成 boost::mutex* mx,并在构造函数中分配它,使其在堆上分配,那么代码也会是线程安全的吗?

  3. 如果问题1和2的答案都是否定的,那么我该如何使每个实例都是线程安全的?


1
为什么人们会谈论“堆栈”和“堆”而不是谈论“自动”和“动态”分配。 - Nawaz
1
在第二点上,绝对没有必要这样做。唯一的原因是将其作为指针(即使是这样,我也会将其作为引用)是为了在构造期间向实例传递互斥量 - 即您有一个要所有实例使用的单个互斥量。 - Nim
3个回答

8

1)如果这个类在堆上分配(temp* T = new temp()),那么这样做是否线程安全(每个实例,而不是所有实例一起)?

是的。由于mx不是类的静态成员,因此每个类实例将有一个锁。

2)如果我将boost::mutex mx -> boost::mutex* mx,并在构造函数中进行分配,以便它在堆上分配,那么代码是否也是线程安全的?

是的。但仅限于每个实例的线程安全。

3)如果问题1和2的答案都是否,则如何使每个实例都线程安全?

答案是肯定的,所以您没问题。

如果有人想知道如何使用一个锁使所有实例都线程安全--您可以将mx设置为类的静态变量。


1
关于您最后的评论,这在很大程度上取决于静态实例的构建位置和方式(即懒加载本身并不具备线程安全性!)。如果您最终采用这种方法,您真的需要审查您的设计。 - Nim
我明白了。我对于懒惰静态变量掌握得不够好。作为一名计算机科学家,我的理解是该术语意味着在变量实际写入之前不会进行分配。这对我来说仍然是线程安全的,但可能会遗漏一些内容。你能告诉我更多吗? - Aater Suleman
1
在给定类中使用静态的两种方法。一种方法是直接将它们声明为静态成员,然后在一个翻译单元中实际定义它们(这里的问题是你依赖于初始化顺序 - 这是不保证的)。解决这个问题的方法是在类的静态函数中将对象声明为静态,并返回对该静态实例的引用 - 这就是我所说的惰性初始化。然而,这并不是固有的线程安全(标准对线程没有任何规定,因此谁构造也不确定)。 - Nim
如果两个线程进入静态函数以获取锁,并且之前没有人调用过此函数,则无法保证谁会构造。解决这个问题的一种方法是在创建线程之前进行某种全局初始化,该初始化调用此静态函数以构造互斥体。另一个选择是在构造“temp”对象时简单地传递一个互斥体,并且只在“temp”中具有对互斥体的引用。 - Nim

3
存储位置与任何东西都无关。

0
是的,在这两种情况下,方法CriticalCode()都将是线程安全的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接