4

我有一个类似于以下的属性:

private:
Foo* myFoo_m;

public:
Foo getMyFoo() const
{
    if (myFoo_m == NULL)
    {
       myFoo_m = new Foo();
       // perform initialization

这在单线程环境中运行良好,但在多线程环境中如何处理呢?我发现的大多数信息都与静态单例有关,但在这种情况下, myFoo 是一个公共实例属性。

我将它从 C#(我可以使用 Lazy)和 Java(我可以使用双重检查锁定)移植过来,但在 C++ 中似乎没有直接的方法可以做到这一点。我不能依赖任何外部库(没有 BOOST),这需要在 windows 和 linux 上工作。我也不能使用 C++11。

任何见解都会很好。我是 C++ 新手。

4

3 回答 3

5

如果您有权访问c++11,则可以使用std::mutexlock 来防止多个线程初始化惰性部分。(注意:std::mutex仅在 VS2012 的 Windows 上可用)

您甚至可以使用以下命令对互斥锁执行范围获取std::lock_guard

private:

std::mutex m_init_mutex;

public:

Foo getMyFoo() const
{
    {
       std::lock_guard<std::mutex> lock(m_init_mutex);
       if (myFoo_m == NULL)
       {
          myFoo_m = new Foo();
          // perform initialization
       }
    }

编辑:OPs 现在声明 C++11 不是一个选项,但也许这个答案在未来会有用

于 2012-11-02T15:59:32.517 回答
4

通过说“没有 C++11”、“没有 Boost 或其他第三方代码”、“必须在 Windows 和 Linux 上工作”,你限制了自己使用特定于实现的锁定机制。

我认为您最好的选择是为自己定义一个简单的锁类,并实现它以在 Linux 上使用 pthread_mutex 并在 Windows 上使用 CriticalSection。可能您已经有了一些特定于平台的代码,以便首先启动线程。

您可以尝试使用 Windows Services for UNIX 之类的方法来避免编写特定于平台的代码,但可能不值得一锁。尽管它是由 Microsoft 提供的,但您可能还是会认为它是一个外部库。

于 2012-11-02T16:15:13.633 回答
1

警告:我没有看到“无 C++11”的要求,所以请忽略答案。


由于 C++11 要求静态变量初始化是线程安全的,因此您可能会认为这是一种“作弊”的简单方法:

Foo init_foo()
{
    // initialize and return a Foo
}

Foo & get_instance_lazily()
{
    static Foo impl = init_foo();
    return impl;
}

该实例将在您第一次调用时被初始化get_instance_lazily(),并且是线程安全的。

于 2012-11-02T16:07:20.973 回答