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

时间:2018-12-03 20:33:12

标签: c memory-management thread-safety windows

我有一个使用关键节的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)
}

1 个答案:

答案 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

_