我在C中实现了单例(静态版本) . 我知道关于这种模式和潜在的线程安全问题的所有争议,但我很好奇为什么这个确切的实现不会停止 . 该程序永不退出,最终仍处于死锁状态 .
singleton.h:
#pragma once
#include <thread>
#include <atomic>
class Singleton
{
public:
static Singleton& getInstance();
private:
std::thread mThread;
std::atomic_bool mRun;
Singleton();
~Singleton();
void threadFoo();
};
singleton.cpp
#include "singleton.h"
Singleton& Singleton::getInstance()
{
static Singleton instance;
return instance;
}
Singleton::Singleton()
{
mRun.store(true);
mThread = std::thread(&Singleton::threadFoo, this);
}
Singleton::~Singleton()
{
mRun.store(false);
if(mThread.joinable())
mThread.join();
}
void Singleton::threadFoo()
{
while(mRun)
{
}
}
main.cpp中
#include "singleton.h"
int main()
{
Singleton::getInstance();
return 0;
}
我所知道的:
-
线程终止
-
主线程卡在连接中
-
它与静态有关,如果我将构造函数设为public并在main()中创建一个Singleton实例,它将正确终止 .
使用Visual Studio 2012.感谢您的建议 .
5 回答
我已将其追溯到
mlock.c
内的void __cdecl _lock(int locknum)
. 当main()
结束时,主线程进入并进入临界区EnterCriticalSection( _locktable[locknum].lock );
. 然后调用Singleton析构函数,另一个线程尝试进入相同的临界区,但是't, and so it starts waiting for main thread to leave the critical section. Main thread, in turn, waits for the other thread. So I guess it'是一个错误 .请参阅标准中的[basic.start.term]:
在主线程上,在
main()
终止后,CRT获取退出锁并调用静态实例析构函数,等待后台线程退出 .在后台线程上,在线程函数终止后,CRT尝试获取退出锁以执行一些线程终止工作 . 这会永远阻塞,因为退出锁是由主线程保持的,它正在等待该线程退出 .
这是由CRT实现引起的简单死锁 . 最重要的是,您不能在Windows上的静态实例析构函数中等待线程终止 .
好的,谢谢大家的提示 . 显然,这种模式实现会导致VC出现死锁 .
在做了一些进一步的研究之后,我发现这个实现基于C 11机制,它在VC中工作 .
singleton.h
singleton.cpp
UPDATE
看起来微软已经意识到了这个问题 . 在VC论坛中,名为"dlafleur"的用户报告了此帖:https://connect.microsoft.com/VisualStudio/feedback/details/747145
这个死锁bug与中的相同
std::thread::join() hangs if called after main() exits when using VS2012 RC
并且它在Visual Studio 2013中不是固定的 .