我有一个使用关键节的Windows DLL(在C中)。一个特定的例程(被多次调用)在首次调用时需要执行一些初始化代码,因此我使用的是关键部分。但是,由于它被调用了很多次,因此我试图避免每次调用该部分时都会产生开销。它似乎正在运行,但是我想知道在具有x64 OS的多处理器(Intel)系统上运行时,是否考虑到内存屏障/栅栏是否存在缺陷?这是精简的代码:
int _isInitialized = FALSE;
CRITICAL_SECTION _InitLock = {0};
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
ARM_SECTION_BEGIN(ul_reason_for_call)
switch (ul_reason_for_call)
{
case (DLL_PROCESS_ATTACH):
InitializeCriticalSection(&_InitLock);
break;
case (DLL_THREAD_ATTACH):
break;
case (DLL_THREAD_DETACH):
break;
case (DLL_PROCESS_DETACH):
DeleteCriticalSection(&_InitLock);
break;
}
return (TRUE);
}
int myproc(parameters...)
{
if (!_isInitialized) // check first time
{
EnterCriticalSection(&_InitLock);
if (_isInitialized) // check it again
{
LeaveCriticalSection(&_InitLock);
goto initialized;
}
... do stuff ...
_isInitialized = TRUE;
LeaveCriticalSection(&_InitLock);
}
initialized:
... do more stuff ...
return(something)
}
答案 0 :(得分:1)
...如果考虑内存障碍/栅栏有缺陷...?
使用volatile
在第二次测试中,使用_isInitialized
的陈旧值显然会使代码冒风险。
if (!_isInitialized) {
EnterCriticalSection(&_InitLock);
if (_isInitialized) // Risk
要确保重新读取_isInitialized
,请使用volatile
。 @JimmyB
// int _isInitialized = FALSE;
volatile int _isInitialized = FALSE;
其他共享数据
在_isInitialized
中分配并在后面的... do stuff ...
代码中使用的... do more stuff ...
以外的其他数据也存在相同的问题,因为优化可能会在第一个{ {1}}。
代码可以使用other_data
。不幸的是,这可能会导致性能下降。替代方法取决于if (!_isInitialized)
内部的内容。
样式
我会将volatile other_data
设置为该函数的局部变量,删除stuff
并避免使用_isInitialized
。
_