Una domanda di ieri sul blocco con doppio controllo ha dato il via a una catena di pensieri che mi ha lasciato insicuro su una situazione semplice. Nel seguente codice, è possibile premere printf
di "Non più sincronizzato"? In questo semplice esempio, i valori sarebbero probabilmente sulla stessa riga della cache, quindi penso che sarebbe meno probabile (assumendo che la possibilità sia> 0% per cominciare).WaitForSingleObject funge da barriera di memoria?
Se la risposta è "No, non è possibile", quindi la mia domanda di follow-up è, piuttosto prevedibile: perché no? Fino a quando i miei pensieri si sono aggrovigliati e avvolti intorno all'assasse multithreading ieri, ho pensato che il codice sarebbe stato sicuro. Ma ora mi chiedo cosa impedisce una lettura stante dalla cache per una delle variabili pa
o pb
. E sarebbe importante se pa, pb
indicasse semplici variabili globali intere piuttosto che memoria malloc'd? La chiamata WaitForSingleObject fornisce una barriera di memoria? O i puntatori dovrebbero essere dichiarati volatili? Così tante domande, così poche frasi.
Aggiornamento: ho finalmente individuato le informazioni che indicano in modo specifico che le funzioni che gestiscono gli oggetti di sincronizzazione utilizzano memory barriers. Doveva essere ovvio, ma stavo avendo problemi a trovare una risposta definitiva. Quindi posso ancora una volta illudermi nel credere di aver capito tutto.
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 esattamente quello che stavo per dire. – tony
Grazie per l'informazione. Ti capita di conoscere un link che discute le funzioni di attesa e le barriere della memoria. Questo è quello che stavo cercando e non l'ho visto. È possibile che io sia solo cieco e mi sia sfuggito qualcosa di ovvio. –
Non sei cieco; è difficile trovare informazioni pertinenti online. MSDN offre una panoramica ragionevolmente buona su http://msdn.microsoft.com/en-us/library/ms686355%28VS.85%29.aspx. –