c-多处理器系统上的关键部分和内存围栏/屏障



我有一个使用关键节的Windows DLL(C语言(。一个被调用多次的特定例程在第一次被调用时需要执行一些初始化代码,所以我使用的是Critical Section。然而,由于它被调用了很多次,我试图避免每次调用时进入该部分的开销。它似乎在工作,但我想知道在x64操作系统的多处理器(英特尔(系统上运行时,考虑到内存屏障/栅栏是否存在缺陷?这是精简的代码:

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)
}

。。。如果考虑到记忆障碍/栅栏有缺陷?

使用volatile

在第二次测试中,代码显然有使用过时的_isInitialized值的风险。

if (!_isInitialized) {
EnterCriticalSection(&_InitLock);
if (_isInitialized)                 // Risk

要确保重新读取_isInitialized,请使用volatile@JimmyB

// int _isInitialized = FALSE;
volatile int _isInitialized = FALSE;

其他共享数据

除了在... do stuff ...中分配并在稍后的... do more stuff ...代码中使用的_isInitialized之外的其他数据由于优化可能在第一个if (!_isInitialized)之前读取other_data而冒着相同问题的风险。

代码可以使用volatile other_data。不幸的是,这可能会导致无法接受的性能拖累。备选方案取决于stuff内部的内容。

样式

我会将_isInitialized设为函数的本地,删除_并避免使用goto

int myproc(parameters...) {
static volatile int isInitialized = FALSE;
if (!isInitialized) {
EnterCriticalSection(&_InitLock);
if (!isInitialized) {
// ... do stuff ...
isInitialized = TRUE;
}
LeaveCriticalSection(&_InitLock);
}
// ... do more stuff ...
return(something)
}

最新更新