WaitForSingleObject служит барьером памяти?

Вопрос вчера об удвоенном - проверенная блокировка запустила цепочку мыслей, которые оставили меня не уверенным в простой ситуации. В следующем коде, это возможный совершить нападки printf из “Больше в синхронизации”? В этом простом примере значения, вероятно, были бы на той же строке кэша, таким образом, я думаю, что это было бы менее вероятно (предположение, что возможность> 0% для начала).

Если ответ, “Нет, это не возможно”. затем мой последующий вопрос, скорее очевидно: почему нет? Пока я не запутал свои мысли и вчера перенес аксель многопоточности, я предположил, что код будет безопасен. Но теперь я задаюсь вопросом, что предотвращает устаревшее чтение от кэша для одной из переменных pa или pb. И это имело бы значение если pa, pb указанный простые глобальные целочисленные переменные, а не malloc’d память? Вызов WaitForSingleObject обеспечивает барьер памяти? Или указатели должны быть объявлены энергозависимые? Столько вопросов, так мало предложений.

Обновление: Я наконец определил местоположение информации, которая действительно конкретно говорит, что функционирует, которые сигнализируют, что объекты синхронизации действительно используют барьеры памяти. Это должно было быть очевидно, но я испытывал затруднения при нахождении категорического ответа. Таким образом, я могу еще раз ввести меня в заблуждение, я понимаю все это.

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

6
задан Mark Wilkins 28 December 2009 в 18:42
поделиться

1 ответ

Неважно, где находится память, и если бы все дело было в когерентности кэша, то объявление переменных волатильными ничего бы не сделало. Семантика волатильности не является ни необходимой, ни достаточной для потокобезопасности, не используйте ее!

На уровне Си/Си++ па и pb могут кэшироваться в регистрах, но после любого вызова функции они будут считаться просроченными. На уровне CPU все функции ожидания используют барьеры, чтобы убедиться, что все работает, как ожидается.

.
4
ответ дан 17 December 2019 в 07:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: