2010-02-07 14 views
6

Stellen Sie sich ein Programm mit zwei Threads vor. Sie laufen den folgenden Code (CAS bezieht sich auf Compare and Swap):Können sich konkurrierende atomare Operationen gegenseitig verhungern?

// Visible to both threads 
static int test; 

// Run by thread A 
void foo() 
{ 
    // Check if value is 'test' and swap in 0xdeadbeef 
    while(!CAS(&test, test, 0xdeadbeef)) {} 
} 

// Run by thread B 
void bar() 
{ 
    while(1) { 
     // Perpetually atomically write rand() into the test variable 
     atomic_write(&test, rand()); 
    } 
} 

Ist es möglich, für Thread B ständig auf Thread A des CAS verursachen, so zum Scheitern verurteilt, dass 0xDEADBEEF nie auf ‚Test‘ geschrieben? Oder bedeutet natürlicher Planungs-Jitter, dass dies in der Praxis nie passiert? Was ist, wenn etwas in der While-Schleife von Thread A getan wurde?

Antwort

6

Als theoretische Angelegenheit, ja. Wenn Sie es irgendwie schaffen könnten, die beiden Threads im Lockstep zu starten, so würde das

Dann würde CAS niemals wahr zurückgeben.

In der Praxis wird dies nie passieren, wenn Threads ein CPU/Core-teilen, und es ist unwahrscheinlich geschehen, wenn Threads auf verschiedenen CPUs oder Cores ausgeführt werden. In der Praxis ist es unglaublich unwahrscheinlich für mehr als ein paar Zyklen zu passieren, und astronomisch unwahrscheinlich für mehr als ein Scheduler Quantum passieren.

Und das ist, wenn dieser Code

void foo() 
{ 
    // Check if value is 'test' and swap in 0xdeadbeef 
    while(!CAS(&test, test, 0xdeadbeef)) {} 
} 

tut, was es zu tun wird, was den aktuellen Wert von test, zu holen ist und vergleichen Sie es mit test zu sehen, ob sie sich geändert hat. In der realen Welt würden Iterationen von CAS durch Code getrennt, der tatsächlich funktioniert hat. Das Schlüsselwort volatile wäre erforderlich, um sicherzustellen, dass der Compiler den Test vor dem Aufruf von CAS abgerufen hat, anstatt anzunehmen, dass eine Kopie, die es noch in einem Register hätte, immer noch gültig wäre.

Oder der Wert, den Sie gegen würde testen wäre nicht der aktuellen Wert von Test sein, sondern eher eine Art zuletzt bekannt Wert. Mit anderen Worten, dieses Codebeispiel ist ein Test der Theorie, aber Sie würden CAS in der Praxis nicht so verwenden, also selbst wenn Sie dies zum Scheitern bringen könnten, sagt es Ihnen nicht unbedingt, wie es gehen könnte scheitern, wenn sie in realen Algorithmen verwendet werden.

+0

Warum sollte es nur zweimal ausgeführt werden? Wenn es den Abruf von Test weg optimiert, ist das nicht der Effekt, dass es für immer * loop *? Der Vergleich und der Austausch werden immer fehlschlagen, weil der Vergleich fortwährend falsch ist, es sei denn, Sie haben Glück und rand() gibt den Wert des Tests zurück, bevor Thread A in die Schleife eingetreten ist und Thread A zur richtigen Zeit ausgeführt wird. –

+0

Auch wenn Sie sagen, unglaublich unwahrscheinlich, meinst du, unwahrscheinlich, dass Sie diesen Code nicht in Produktionssoftware verwenden würde? Es wäre interessant zu versuchen, eine vereinfachte Wahrscheinlichkeit zu berechnen. –

+0

Wenn ich persönlich sage unglaublich unwahrscheinlich, wenn es um ein Threading-Problem geht, ich meine, ich will es behoben, so dass es wirklich nicht passiert. Ich hatte zu viele "nicht wird passieren" explodieren auf mich. –

2

Starvation kann sicher in solchen Fällen geschehen. Zitiert the wikipedia page,

Es wird auch, dass der weithin verfügbare Atom-bedingte Primitiven, CAS und LL/SC gezeigt worden ist, kann nicht Hunger freien Implementierungen von vielen gemeinsamen Daten Strukturen ohne Speicherkosten bieten wachsen linear in der Anzahl der Threads. Wartefreie Algorithmen sind daher selten, sowohl in der Forschung als auch in der Praxis .

(Siehe den Link von der betreffenden Seite für den mathematischen Beweis).

+0

Je nachdem, wie die CAS verwendet wird, kann es oft möglich sein, um sicherzustellen, dass keine Aufgabe außer blockiert werden, wenn eine andere Aufgabe vorwärts Fortschritte macht. Wenn die Anzahl der zu bearbeitenden Arbeiten begrenzt ist, bedeutet dies wiederum, dass jede Aufgabe letztendlich abgeschlossen sein wird. Die maximale Zeit für eine bestimmte Aufgabe kann als eine Funktion der Gesamtmenge der Arbeit, die ankommen wird, berechnet werden.In einem systemfreien System würde die Zeit, die eine Aufgabe nach dem Start benötigt, begrenzt sein, selbst wenn die Arbeitsbelastung nicht gegeben ist, aber es ist immer noch sinnvoll, eine zeitlich begrenzte Zeit zu haben. – supercat

Verwandte Themen