c++ - 在初始化完成之前在单例上调用方法

标签 c++ singleton

将旧的 Visual Studio 2003 项目转换为 2015 时,我遇到了应用程序在启动后立即卡住的问题。我似乎无法从调试器中获得太多信息,因为应用程序并没有真正崩溃。

当我暂停调试器时,它总是指向同一行代码,即单例 GetInstance 方法中的静态变量。这使得应用程序看起来像是在等待它被初始化。此对象的构造函数正在调用一个使用相同 GetInstance 方法的方法,因此在构造函数结束之前正在使用该实例。

代码是这样工作的:

//A.cpp
A::A()
{
    B::GetInstance()->DoSomething();
}

A* A::GetInstance()
{
    static A instance; // The debugger always points out that this line is next to be executed after pausing the application
    return &instance;
}

//B.cpp
void B::DoSomething()
{
    A::GetInstance()->DoSomethingElse();
}

我知道这段代码可以改进,也有解决方法,但我想知道为什么这段代码在 Visual Studio 2003 中运行良好,但在 Visual Studio 2015 中却出现问题。

提前致谢。

最佳答案

@Lehu 在他们删除的答案中大部分是正确的。这是一个循环引用,如果不被互斥量阻止,它将递归。这是发生了什么:

  1. B::DoSomething() 调用
  2. B::DoSomething() 调用 A::GetInstance()
  3. A::GetInstance() 调用构造函数A::A() 构造static A 实例。这将锁定围绕 instance 创建的关键部分,以确保作业可以在不中断的情况下完成。
  4. A::A() 调用 B::DoSomething(); 看到圆形成了吗?
  5. B::DoSomething() 调用 A::GetInstance()
  6. A::GetInstance() 尝试访问 instance,但 instance 尚未完成构建,因此执行会暂停直到可以。

不幸的是,在第 6 步完成之前,第 3 步无法完成 这是一个典型的死锁:3 正在等待 6 完成,而 6 正在等待 3 完成。 To Quote Pvt. Hudson, "Game over, man! Game over!"

编辑:仔细想想,互斥锁这个词不太合适。 Crtitcal Section围绕获取静态变量 instance 更合适。

我要演示的 MCVE 剪辑:

struct A
{
    A();
    static A* GetInstance()
    {
        static A instance; 
        return &instance;
    }
    void DoSomethingElse()
    {

    }
};
struct B
{
    void DoSomething()
    {
        A::GetInstance()->DoSomethingElse();
    }
    static B* GetInstance()
    {
        static B instance; 
        return &instance;
    }
};

A::A()
{
    B::GetInstance()->DoSomething();
}


int main()
{
    B::GetInstance()->DoSomething();
}

关于c++ - 在初始化完成之前在单例上调用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40295345/

相关文章:

c++ - 当 key 是涉及虚拟继承的基类指针时,访问 std::unordered_map 项会崩溃

c++ - 即时修改输入流数据

c++ - 多层继承中的virtual关键字

scala - 为什么 Scala 2.10 在匹配单例类型时给出 'match may not be exhaustive' 警告?

java - 包装不可编辑的单例类

c++ - 如何在 Eclipse 中使用动态库?

c++ - 我的代码正确,但Leetcode平台不接受。 (之字形转换)

php - 从单例类 PHP 中检索数据

java - 为什么在将 CGLIB 原型(prototype)注入(inject) Singleton 的情况下,每次对原型(prototype)的访问都会创建一个新对象?

java - 同时多次调用方法的问题