Macht die Reihenfolge der Entriegelungsmutexe hier einen Unterschied?

8

Nehmen wir an, ich habe zwei Variablen, protected_var1 und protected_var2 . Nehmen wir weiter an, dass diese Variablen über mehrere Threads aktualisiert werden und ziemlich unabhängig davon sind, dass normalerweise das eine oder das andere, aber nicht beide bearbeitet werden - so haben beide ihre eigenen Mutex-Wächter für Effizienz.

Angenommen:

- Sperren Sie Mutexe immer in der richtigen Reihenfolge (Mutex1, dann Mutex2) in meinem Code in Bereichen, in denen beide Sperren erforderlich sind.

- Beide Mutexe werden an vielen anderen Stellen von ihnen selbst benutzt (wie zB mutex1 sperren, oder einfach mutex2 sperren).

Macht die Reihenfolge, in der ich die Mutexe am Ende einer Funktion mit beiden freischalte, einen Unterschied in dieser Situation?

%Vor%

Vor langer Zeit wurde mir in einem Interview eine Frage bezüglich dieser Situation gestellt, und ich stellte fest, dass die Antwort ja war - die Reihenfolge dieser beiden Freischaltungen ist von Bedeutung. Ich kann nicht für das Leben von mir herausfinden, wie sich ein Deadlock daraus ergeben könnte, wenn die Schlösser immer in der gleichen Reihenfolge erhalten werden, wo immer beide benutzt werden.

    
John Humphreys - w00te 23.02.2012, 14:20
quelle

9 Antworten

7
  

Ich kann nicht für das Leben von mir herausfinden, wie sich ein Deadlock daraus ergeben könnte, wenn die Schlösser immer in der gleichen Reihenfolge erhalten werden, wo immer beide benutzt werden.

Unter diesen Umständen glaube ich nicht, dass die Reihenfolge, in der die Mutexe entsperrt werden, die Ursache für einen Deadlock sein könnte.

Da pthread_mutex_unlock() nicht blockiert, werden beide Mutexe immer entsperrt, unabhängig von der Reihenfolge der beiden Aufrufe.

Beachten Sie, dass wenn Sie versuchen, Sperren zwischen die beiden Entsperrungsanrufe zu erwerben, dies das Bild vollständig ändern kann.

    
NPE 23.02.2012, 14:23
quelle
11

Die Reihenfolge sollte keine Rolle spielen, solange Sie nicht versuchen zu erwerben eine weitere Sperre zwischen den Releases. Das Wichtigste ist immer erwirb die Schlösser in der gleichen Reihenfolge; Andernfalls riskieren Sie einen Stillstand.

BEARBEITEN:

Um die Einschränkung zu erweitern: Sie müssen eine strenge Reihenfolge festlegen die Mutexe, z.B. mutex1 geht vor mutex2 (aber diese Regel ist gültig für beliebig viele Mutexe). Sie können nur eine Sperre für einen Mutex anfordern, wenn Sie Halte nicht einen Mutex, der in der Reihenfolge danach kommt; z.B. du darfst nicht Fordern Sie eine Sperre für mutex1 an, wenn Sie eine Sperre für mutex2 haben. Jederzeit Diese Regeln werden respektiert, Sie sollten in Sicherheit sein. In Bezug auf Freigabe, wenn Sie mutex1 freigeben, dann versuchen Sie es vorher wieder zu erwerben Wenn Sie mutex2 freigeben, haben Sie die Regel verletzt. In dieser Hinsicht kann es ein Vorteil in Bezug auf eine Stapel-ähnliche Reihenfolge sein: zuletzt erworben ist immer der erste veröffentlicht. Aber es ist eine Art indirekter Effekt: der Regel ist, dass Sie eine Sperre auf mutex1 nicht anfordern können, wenn Sie eine an halten %Code%. Unabhängig davon, ob Sie bei mutex2 eine Sperre hatten hat die Sperre für mutex1 oder nicht erhalten.

    
James Kanze 23.02.2012 14:26
quelle
3

Es spielt keine Rolle für die Korrektheit der Verriegelung. Der Grund ist, dass, selbst wenn ein anderer Thread darauf wartet, Mutex1 und dann Mutex2 zu sperren, der schlimmste Fall ist, dass er sofort geplant wird, sobald Sie Mutex1 freigeben (und Mutex1 erwirbt). Dann blockiert es das Warten auf Mutex2, und der Thread, nach dem du fragst, wird freigegeben, sobald es wieder eingeplant ist, und es gibt keinen Grund, der nicht bald eintreten sollte (sofort, wenn dies die einzigen beiden Threads sind) / p>

Es kann also in der exakten Situation zu kleinen Kosten in der Leistung kommen, im Vergleich dazu, wenn Sie zuerst Mutex2 freigegeben haben und es daher nur einen Neuterminierungsvorgang gab. Nichts, was man normalerweise vorhersagen oder befürchten müsste, sondern alles innerhalb der Grenzen von "Planung ist oft nicht deterministisch".

Die Reihenfolge, in der Sie die Sperren freigeben, könnte jedoch die Planung im Allgemeinen beeinflussen. Angenommen, zwei Threads warten auf Ihren Thread und einer von ihnen ist auf Mutex1 blockiert, während der andere auf Mutex2 blockiert ist. Es kann sich herausstellen, dass, egal welche Sperre Sie zuerst loslassen, dieser Thread zuerst ausgeführt wird, nur weil Ihr Thread seine Begrüßung überlebt hat (mehr als eine ganze Zeitscheibe verbraucht) und daher entschifft wird, sobald etwas anderes ausgeführt werden kann. Aber das kann nicht zu einem Fehler in einem ansonsten korrekten Programm führen: Sie dürfen sich nicht auf Ihren entplanten Thread verlassen, sobald er die erste Sperre aufhebt. Die Reihenfolge der beiden wartenden Threads, die beide gleichzeitig ausgeführt werden, wenn Sie mehrere Kerne haben, oder die beiden, die sich auf einem Kern abwechseln, müssen alle gleich sicher sein, unabhängig davon, in welcher Reihenfolge Sie die Sperren freigeben.

    
Steve Jessop 23.02.2012 14:56
quelle
1

Die Reihenfolge der Entsperrung kann nicht zu Deadlocks führen. Wenn jedoch die Gelegenheit gegeben wird, empfehle ich, sie in umgekehrter Verriegelungsreihenfolge zu entsperren. Dies hat einen vernachlässigbaren Einfluss auf die Ausführung des Codes. Entwickler sind jedoch daran gewöhnt, in Bereichen zu denken, und Bereiche "schließen" in umgekehrter Reihenfolge. Sie sehen sie in umgekehrter Reihenfolge, um einfach an die Lösungsschranken zu denken. Das bringt mich zum zweiten Punkt, nämlich dass es in den meisten Fällen am sichersten ist, die direkten Aufrufe zum Sperren und Entsperren durch einen Stack-basierten Wächter zu ersetzen, der sie für Sie aufruft. Dies führt zu dem höchsten Grad an Korrektheit für die geringste mentale Anstrengung, und ist auch sicher in der Gegenwart von Ausnahmen (die wirklich mit einer manuellen Entsperrung misten können)!

Ein einfacher Wächter (es gibt viele da draußen ... das ist nur ein schnelles Selbstdrehen):

%Vor%     
Cort Ammon 04.09.2013 03:07
quelle
0

Nein, das macht nichts. Ein Deadlock kann daraus nicht resultieren; Beide Entriegelungsoperatoren sind garantiert erfolgreich (Bar-Heap-Korruption oder ähnliche Probleme).

    
Collin Dauphinee 23.02.2012 14:24
quelle
0

Die Reihenfolge der Entsperrung ist hier kein Problem, aber die Reihenfolge der Sperrung kann ein Problem sein.

Überlegen Sie:

%Vor%

Dies kann zu einem Deadlock führen, da foo mutex1 gesperrt hat und jetzt auf mutex2 wartet, während bar mutex2 gesperrt hat und jetzt auf mutex1 wartet. Es ist also eine gute Idee, sicherzustellen, dass geschachtelte Mutex-Sperren immer in derselben Reihenfolge gesperrt werden.

    
DarkDust 23.02.2012 14:26
quelle
0

Was ich sehen kann ist, dass, wenn eine andere Operation mutex2 verwendet und sie für eine lange Zeit hält, Ihre foo() -Funktion nach pthread_mutex_lock(&mutex1); hängen bleibt und wahrscheinlich einen Leistungseinbruch hat.

    
Gui13 23.02.2012 14:33
quelle
0

Solange var1 und var2 gesperrt sind, sind sie in derselben Reihenfolge gesperrt, in der Sie sicher sind, unabhängig von der freigebenden Reihenfolge. In der Reihenfolge, in der sie gesperrt wurden, wird das RAII-Freigabeverhalten in STL- und BOOST-Sperren freigegeben.

    
Unknown1987 23.02.2012 14:34
quelle
0
%Vor%

Ich denke, das kann den Deadlock verhindern

    
Ali Kayaten 23.09.2016 19:14
quelle