在C ++ 11之前在C ++中实现Double Check Lock Pattern是否安全

时间:2017-02-08 09:03:02

标签: c++ multithreading

class SelfTesting
{
private:
    char * pChar;
    SelfTesting()
    {
        pChar = new char[1024 * 1024 * 1024];
    }
public:
    static SelfTesting * pSelf;

    static SelfTesting& GetInst()
    {
        if (!pSelf)
        {
            boost::lock_guard<boost::mutex> lock(g_boost_mutex);
            if (!pSelf)
            {
                pSelf = new SelfTesting;
            }
        }
        return *pSelf;
    }
};

一般来说,我知道问题是由以下原因引起的:

1. allocate memory for `SelfTesting`
2. store the pointer to the allocated memory in `pChar`
3. initialize `SelfTesting`
  1. 如果其他线程在步骤2和3之间触摸指针,则会发生数据争用情况。 From
  2. 如果指针复制不是原子的,也会发生数据争用情况。 From
  3. 我知道我可以使用本地静态变量在C ++ 11中实现这种模式。我的问题是上面的实现线程是安全的,或者当我在C ++ 11之前使用C ++标准时它是未定义的。 boost::mutex pSelf确保lockDictionary<DateTime, List<double>>死后会更新吗?

1 个答案:

答案 0 :(得分:3)

正如所写,这种模式在任何版本的C ++中都不安全。在C ++ 11术语中,您在外部读取pSelf和写入pSelf之间存在数据争用。

一般来说,在C ++之前的版本11中,没有保证多线程代码的安全性。关于C ++ 11最重要的一点是它在C ++执行的抽象模型中引入了可能首先存在多个执行线程的想法。在此之前,对于多线程执行绝对没有任何保证,因为这个概念并不存在。就标准而言,任何有多个线程的情况都是未定义的,因为它没有定义线程是什么。

这基本上意味着您在C ++ 98中编写的任何多线程代码完全取决于您使用的特定实现。主流编译器有一些你可以依赖的东西,尽管在C ++ 11的开发中,在有多个线程时,在各种编译器中发现了几个行为(特别是优化),这些行为实际上并不安全。

但这一切都无关紧要,因为你所编写的代码从来没有保证在我所知道的任何编译器中都是安全的。使用Visual C ++,您可以通过使pSelf volatile(VC ++处理的volatile变量类似于原子)使其安全,但这在GCC中不起作用。在GCC中,您必须使用原子内在函数或Boost.Atomic库。