将旧的 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 在他们删除的答案中大部分是正确的。这是一个循环引用,如果不被互斥量阻止,它将递归。这是发生了什么:
B::DoSomething()
调用B::DoSomething()
调用A::GetInstance()
A::GetInstance()
调用构造函数A::A()
构造static A 实例
。这将锁定围绕instance
创建的关键部分,以确保作业可以在不中断的情况下完成。A::A()
调用B::DoSomething();
看到圆形成了吗?B::DoSomething()
调用A::GetInstance()
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/