Вчера вопрос о проверке с двойным проверкой запустил цепочку мыслей, которая оставила меня неуверенным в простой ситуации. В следующем коде можно ли нажать printf
на «Больше не синхронизироваться»? В этом простом примере значения, вероятно, будут в одной и той же строке кэша, поэтому я думаю, что это будет менее вероятно (предполагая, что возможность начинается> 0%).Неужели WaitForSingleObject работает как барьер памяти?
Если ответ: «Нет, это невозможно». Тогда мой вопрос о последующей деятельности, скорее, предсказуем: почему бы и нет? До тех пор, пока вчера мои мысли не запутались и не обернулись вокруг многопоточного акселя, я предположил, что код будет в безопасности. Но теперь мне интересно, что предотвращает устаревшее чтение из кеша для одной из переменных 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 точно, что я собирался сказать. – tony
Благодарим вас за информацию. Вы случайно знаете ссылку, в которой обсуждаются функции ожидания и барьеры памяти. Это то, что я искал и не видел. Вполне возможно, я просто слеп и пропустил что-то очевидное. –
Ты не слепой; трудно найти соответствующую информацию в Интернете. MSDN предлагает достаточно хороший обзор на http://msdn.microsoft.com/en-us/library/ms686355%28VS.85%29.aspx. –