代码之家  ›  专栏  ›  技术社区  ›  Neil Weicher

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

  •  2
  • Neil Weicher  · 技术社区  · 6 年前

    我有一个使用关键部分的Windows DLL(C)。一个被多次调用的特定例程在第一次调用时需要执行一些初始化代码,因此我使用了一个关键部分。然而,由于它被调用了很多次,我试图避免每次调用时进入该节的开销。它似乎可以工作,但我想知道,在使用x64操作系统的多处理器(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 回复  |  直到 6 年前
        1
  •  3
  •   chux    6 年前

    ... 考虑到内存屏障/围栏,是否存在缺陷?

    使用 volatile

    _isInitialized

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

    确保重读 ,使用 不稳定的 . @JimmyB

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

    分配给 ... do stuff ... 并在以后的版本中使用 ... do more stuff ... 由于优化,代码可能存在同样的问题 other_data if (!_isInitialized) .

    volatile other_data . 不幸的是,这可能会导致不可接受的性能阻力。其他选择取决于里面的东西 stuff

    风格

    我会 在函数的本地,删除 _ 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)
    }