将旧的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中中断。
提前致谢。
答案 0 :(得分:2)
B::DoSomething()
名为B::DoSomething()
调用A::GetInstance()
A::GetInstance()
调用构造函数A::A()
来构造static A instance
。这将锁定instance
创建的关键部分,以确保可以在不中断的情况下完成作业。A::A()
调用B::DoSomething();
查看圈子形成?B::DoSomething()
调用A::GetInstance()
A::GetInstance()
尝试访问instance
,但instance
尚未完成构建,因此执行会停止,直到可以。 不幸的是,第3步无法完成,直到第6步完成。这是一个典型的死锁:3正在等待6完成,6正在等待3完成。 To Quote Pvt. Hudson, "Game over, man! Game over!"
编辑:考虑到这一点,互斥量并不是一个非常正确的术语。获取静态变量instance
的{{3}}更合适。
我剪切了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();
}