代码之家  ›  专栏  ›  技术社区  ›  Mark Wilkins

WaitForSingleObject是否充当内存屏障?

  •  6
  • Mark Wilkins  · 技术社区  · 15 年前

    昨天一个关于双重检查锁定的问题引发了一连串的思考,让我对一个简单的情况不确定。在下面的代码中,是否可以点击 printf _不再同步__?在这个简单的示例中,值可能位于同一缓存线上,因此我认为它不太可能(假设可能性从0%开始)。

    如果答案是,不,这是不可能的。,那么我的后续问题是,相当可预见的:为什么不呢?直到昨天我的思想被多线程AXEL缠住了,我才认为代码是安全的。但是现在我想知道是什么阻止了对其中一个变量从缓存中进行过时的读取 pa pb . 如果 pa, pb 指向简单的全局整型变量而不是malloc_d内存?WaitForSingleObject调用是否提供内存屏障?还是应该将指针声明为易失性?问题太多,句子太少。

    更新 :我最后找到的信息确实特别说明了信号同步对象确实使用的函数 memory barriers .这本应该是显而易见的,但我很难找到一个明确的答案。所以我可以再一次欺骗自己,让自己相信我了解这一切。

    int i1 = 0;
    int i2 = 0;
    int reads = 0;
    int done = 0;
    int *pa = NULL;
    int *pb = NULL;
    HANDLE hSync = NULL;
    
    DWORD WriteThread( LPVOID pvParam )
    {
       while( !done )
          {
          WaitForSingleObject( hSync, INFINITE );
          (*pa)++;
          (*pb)++;
          ReleaseSemaphore( hSync, 1, NULL );
          }
       return 0;
    }
    
    DWORD ReadThread( LPVOID pvParam )
    {
       while( !done )
          {
          WaitForSingleObject( hSync, INFINITE );
          if ( *pa != *pb )
             {
             printf( "No longer in sync: %d, %d\n", *pa, *pb );
             exit( 1 );
             }
          ReleaseSemaphore( hSync, 1, NULL );
          reads++;
          }
       return 0;
    }
    
    int main( int argc, char* argv[] )
    {
       DWORD dwID;
    
       // malloc'd memory
       pa = (int*)malloc( sizeof( int ));
       pb = (int*)malloc( sizeof( int ));
    
       // Is a simple global variable different?
       //pa = &i1;
       //pb = &i2;
    
       *pa = 0;
       *pb = 0;
    
       hSync = CreateSemaphore( NULL, 1, 1, NULL );
       CreateThread( NULL, 0, WriteThread, NULL, 0, &dwID );
       CreateThread( NULL, 0, ReadThread, NULL, 0, &dwID );
    
       while ( *pa < 1000000 )
          Sleep( 1 );
       done = 1;
    
       return 0;
    }
    
    1 回复  |  直到 15 年前
        1
  •  4
  •   Marcelo Cantos    15 年前

    内存在哪里并不重要,如果它都是关于缓存一致性的,那么声明变量volatile对修复它没有任何作用。volatile的语义对于线程安全既不必要也不充分;不要使用它!

    在C/C++级别,PA和PB可以在寄存器中缓存,但在任何函数调用之后都会被认为是过时的。在CPU级别,所有的等待函数都使用屏障来确保所有事情都按预期工作。