Ist es sicher, 'unsichere' Thread-Funktionen zu verwenden?

8

Bitte entschuldigen Sie meinen leicht humorvollen Titel. Ich verwende (offensichtlich) zwei verschiedene Definitionen des Wortes "sicher".

Ich bin ziemlich neu im Threading (naja, ich habe seit vielen Jahren Threading verwendet, aber nur sehr einfache Formen davon). Jetzt stehe ich vor der Herausforderung, parallele Implementierungen einiger Algorithmen zu schreiben, und die Threads müssen mit den gleichen Daten arbeiten. Betrachten Sie den folgenden Anfängerfehler:

%Vor%

Ein Anfänger könnte erwarten, dass der obige Code die Nachricht 20000000 anzeigt. In der Tat, zuerst value ist gleich 0 , und dann wir inc it 20000000 mal. Da die inc -Prozedur jedoch nicht 'atomisch' ist, werden die beiden Threads in Konflikt geraten (ich denke, dass inc drei Dinge tut: Es liest, inkrementiert und speichert), und so viele inc s wird effektiv "verloren". Ein typischer Wert, den ich aus dem obigen Code erhalte, ist 10030423 .

Die einfachste Problemumgehung besteht darin, InterlockedIncrement statt Inc (was in diesem dummen Beispiel viel langsamer sein wird, aber das ist es nicht die Stelle). Eine andere Problemumgehung ist, das inc innerhalb eines kritischen Abschnitts zu platzieren (ja, das wird auch in diesem albernen Beispiel sehr langsam sein).

Jetzt sind Konflikte in den meisten echten Algorithmen nicht üblich. In der Tat könnten sie sehr ungewöhnlich sein. Einer meiner Algorithmen erstellt DLA-Fraktale , und eine der Variablen, die ich ab und zu als inc verwende, ist die Anzahl der adsorbierten Partikel. Konflikte sind hier sehr selten, und vor allem ist es mir egal, ob die Variable 20000000, 20000008, 20000319 oder 19999496 summiert. Daher ist es verlockend, nicht InterlockedIncrement zu verwenden. oder kritische Abschnitte, da sie den Code nur aufblähen und ihn (marginal) langsamer machen, als dass er (soweit ich das sehen kann) davon profitiert.

Meine Frage ist jedoch: Kann es schwerwiegende Folgen von Konflikten geben als ein leicht "falscher" Wert der inkrementierenden Variable? Kann das Programm beispielsweise abstürzen?

Zugegebenermaßen kann diese Frage albern erscheinen, denn schließlich sind die Kosten für die Verwendung von InterlockedIncrement anstelle von inc ziemlich niedrig (in vielen Fällen, aber nicht alle!), und so ist es (vielleicht) dumm nicht um sicher zu spielen. Aber ich denke auch, dass es gut wäre zu wissen, wie das auf theoretischer Ebene wirklich funktioniert, also halte ich diese Frage für sehr interessant.

    
Andreas Rejbrand 07.01.2012, 13:13
quelle

1 Antwort

10

Ihr Programm wird niemals aufgrund eines Wetters auf dem Inkrement einer Ganzzahl abstürzen, die nur als Anzahl verwendet wird. Alles was schief gehen kann ist, dass Sie die richtige Antwort nicht bekommen. Wenn Sie die ganze Zahl als Index für ein Array verwenden oder vielleicht ein Zeiger, könnten Sie Probleme haben.

Wenn Sie diesen Wert nicht unglaublich häufig erhöhen, ist es schwer vorstellbar, dass ein verkettetes Inkrement so teuer ist, dass Sie den Leistungsunterschied bemerken.

Der effizienteste Ansatz besteht darin, dass jeder Thread seine eigene private Anzahl erhält. Dann summieren Sie alle einzelnen Threads, wenn Sie die Threads am Ende der Berechnung verbinden. Auf diese Weise erhalten Sie das Beste aus beiden Welten. Kein Streit über das Inkrementieren und die richtige Antwort. Natürlich müssen Sie Maßnahmen ergreifen, um sicherzustellen, dass Sie nicht von false sharing .

    
David Heffernan 07.01.2012, 13:19
quelle