2012-02-27 3 views
0

Je ne comprends pas pourquoi cela se produit. Prenez le morceau de code suivant psuedo:Pourquoi mes opérations atomiques se déroulent-elles dans un ordre inattendu?

volatile unsigned long count = 0; 
volatile unsigned long sum = 0; 

void ThreadFunction() { 
    InterlockedIncrement(&count); 
    InterlockedExchangeAdd(&sum, rand()); 
} 

int main() { 
    for (int i = 0; i < 10; ++i) { 
     // This is the problematic instruction 
     InterlockedExchange(&count, 0); 
     InterlockedExchange(&sum, 0); 

     std::vector<boost::thread> threads(i); 
     for (int j = 0; j < i; ++j) 
      threads[j] = boost::thread(ThreadFunction); 

     while (count != i) 
      Sleep(0); 
    } 
} 

Sur la première exécution du programme, lorsque i = 0, l'échange atomique sur sum du thread principal se produit généralement après le fil donné naissance a terminé. Les opérations sur count se produisent toujours dans le bon ordre.

Cela ne se produit qu'une fois; il fait les opérations dans le bon ordre pour le reste de la boucle. Cela n'arrive pas toujours, mais c'est généralement le cas. Si je casse dans le débogueur ou dors avant l'ajout atomique, les instructions seront exécutées dans le bon ordre.

De toute façon, le résultat est que la valeur écrite par le thread est remplacée par le 0 qui aurait dû se produire avant même que le thread ait été lancé.

Pourquoi cela se produit-il? Pourquoi ne puis-je pas compter sur le processeur pour compléter les instructions atomiques que je lui ai données dans l'ordre dans lequel je les ai données? Une opération atomique n'implique-t-elle pas une barrière de mémoire pour empêcher le réordonnancement?

Remarque secondaire, cela se produit avec Visual Studio 2010. Je n'ai pas d'autres versions à tester avec.

+0

Je doute que ce soit votre problème, mais les variables 'count' et' sum' devraient également être annotées comme '__align (32)' comme indiqué dans la documentation de ['InterlockedIncrement()'] (http: // msdn.microsoft.com/en-us/library/windows/desktop/ms683614(v=vs.85).aspx): "La variable pointée par le paramètre Addend doit être alignée sur une limite de 32 bits, sinon, La fonction se comportera de manière imprévisible sur les systèmes x86 multiprocesseurs et sur les systèmes autres que x86. " –

+1

"lorsque i = 0, l'échange atomique sur la somme du thread principal se produit généralement après la fin du thread engendré" - quand 'i == 0' aucun thread n'est engendré -' j

+0

Ce code est juste destiné à montrer ce que je fais, il n'est pas destiné à compiler. Mes variables sont toutes alignées sur 32 bits. –

Répondre

7

Une opération atomique est atomique dans le sens où elle est ininterrompue. Il ne sera pas exécuté ou complètement terminé sans qu'un autre thread obtienne un look-in. Cela ne veut pas dire que 20 opérations atomiques se produiront toujours dans le même ordre, cela reste soumis aux aléas du multi-threading.

En fonction de la vitesse de vos discussions commencent, ils peuvent être séquencés comme main, thrd1, main, thrd2, main, thrd3, ... ou main, main, main, main, thrd1, main, main, thrd2, ... ou toute autre combinaison (si je suis assez certain main aurait toujours d'abord simplement parce que son fonctionnement atomique est avant de commencer les discussions).

+0

Je viens de me rendre compte que j'ai mal ordonné les opérations atomiques. Mon mal, merci. Je devrais incrémenter * après * l'ajout. –

Questions connexes