我正在开发一个从.dll运行的游戏引擎。在里面,有一个导出函数,它返回对在其中声明的静态类的引用,如下所示:
__forceinline __declspec(dllexport) STATE* NF3DGetEngineState(void)
{
static STATE s_State;
return &s_State;
}
其中STATE
是一个管理所有组件的类,并具有通过关键部分访问它们的函数:
void Set(int val)
{
EnterCriticalSection(&CriticalSection);
ClassMember = val;
LeaveCriticalSection(&CriticalSection);
}
其中“CriticalSection”是CRITICAL_SECTION
类的STATE
成员,当然是初始化的。我使用这些函数的上下文是:
NF3DGetEngineState()->Set(10);
问题是:这个代码线程安全吗?
根据我的学习,返回对静态声明的引用不是线程安全的。
我能做些什么来做到这一点?
答案 0 :(得分:3)
哪个是您的C ++版本?如果它是C ++ 11或更高版本,那么代码就像它获得的线程安全一样。如果是11之前的版本,则首次拨打NF3DGetEngineState
是不安全的。
澄清。
不是返回对静态变量的引用'不是线程安全的'。相反,它是100%安全的。什么不是线程安全的预C ++ 11是静态变量初始化本身。 pre-C ++ 11对第一次对函数的并发调用没有任何保证。实际上,如果你第一次同时进入这个函数,我使用的所有11-C ++编译器都会出现问题。原因是,编译器在使用静态变量时生成的代码看起来大致如下:
static bool static_var_initialized = false;
if (!static_var_initialized) {
new (&static_var) StaticVarType(); // Explicit constructor call
static_var_initialized = true;
}
显然,如果在静态变量设置为true之前碰巧多次调用此函数,则有可能多次调用构造函数。
在C ++ 11中,保证它永远不会发生,构造函数只会被调用一次。它还保证没有线程会看到未构造的值。