Was ist ein Thread-Konflikt?

119

Kann jemand bitte einfach erklären, was Thread-Konflikt ist?

Ich habe es gegoogelt, kann aber keine einfache Erklärung finden.

Tony der Löwe
quelle
9
Schreiben Sie also auf, was Ihre vagen Gedanken dazu sind, damit wir sehen können, wo Sie möglicherweise abwesend sind oder ob Ihr Verständnis korrekt ist.
James Black

Antworten:

87

Im Wesentlichen ist ein Thread-Konflikt eine Bedingung, bei der ein Thread auf eine Sperre / ein Objekt wartet, die bzw. das derzeit von einem anderen Thread gehalten wird. Daher kann dieser wartende Thread dieses Objekt erst verwenden, wenn der andere Thread dieses bestimmte Objekt entsperrt hat.

TastaturP
quelle
53
Diese Antwort ist unvollständig (wie die meisten anderen auch). Während ein Schloss eine Art von Sache ist, über die es Streit geben kann, ist es bei weitem nicht die einzige solche Sache. Es kann auch zu Konflikten um sperrenlose Ressourcen kommen. (Wenn beispielsweise zwei Threads dieselbe ganze Zahl atomar inkrementieren, kann es aufgrund von Cache-Ping-Ponging zu Konflikten kommen. Es sind keine Sperren beteiligt.)
David Schwartz
Bei einer globalen Interpreter-Sperre (GIL) wie in CPython, bei der ein Thread immer die GIL abrufen muss, sind daher standardmäßig mehrere Threads im selben Prozess umstritten.
Acumenus
Ich denke, Sie haben es in Bezug auf Deadlock erklärt, aber es unterscheidet sich sehr vom Deadlock.
Harshit Gupta
184

Einige Antworten scheinen sich auf Sperrenkonflikte zu konzentrieren, aber Sperren sind nicht die einzigen Ressourcen, auf denen Konflikte auftreten können. Konflikt ist einfach, wenn zwei Threads versuchen, entweder auf dieselbe Ressource oder auf verwandte Ressourcen so zuzugreifen, dass mindestens einer der konkurrierenden Threads langsamer ausgeführt wird als wenn die anderen Threads nicht ausgeführt würden.

Das offensichtlichste Beispiel für einen Konflikt ist ein Schloss. Wenn Thread A eine Sperre hat und Thread B dieselbe Sperre erlangen möchte, muss Thread B warten, bis Thread A die Sperre aufhebt.

Dies ist plattformspezifisch, aber der Thread kann langsamer werden, selbst wenn er nie warten muss, bis der andere Thread die Sperre aufhebt! Dies liegt daran, dass eine Sperre irgendeine Art von Daten schützt und die Daten selbst häufig auch umstritten sind.

Stellen Sie sich beispielsweise einen Thread vor, der eine Sperre erwirbt, ein Objekt ändert, dann die Sperre aufhebt und einige andere Aufgaben ausführt. Wenn zwei Threads dies tun, selbst wenn sie nie um die Sperre kämpfen, laufen die Threads möglicherweise viel langsamer als wenn nur ein Thread ausgeführt würde.

Warum? Angenommen, jeder Thread läuft auf einem eigenen Kern auf einer modernen x86-CPU und die Kerne teilen sich keinen L2-Cache. Mit nur einem Thread bleibt das Objekt möglicherweise die meiste Zeit im L2-Cache. Wenn beide Threads ausgeführt werden, stellt der andere Thread jedes Mal, wenn ein Thread das Objekt ändert, fest, dass sich die Daten nicht in seinem L2-Cache befinden, da die andere CPU die Cache-Zeile ungültig gemacht hat. Auf einem Pentium D führt dies beispielsweise dazu, dass der Code mit einer FSB-Geschwindigkeit ausgeführt wird, die viel geringer ist als die L2-Cache-Geschwindigkeit.

Da Konflikte auftreten können, auch wenn die Sperre selbst nicht angefochten wird, können Konflikte auch auftreten, wenn keine Sperre vorhanden ist. Angenommen, Ihre CPU unterstützt ein atomares Inkrement einer 32-Bit-Variablen. Wenn ein Thread eine Variable weiter inkrementiert und dekrementiert, ist die Variable die meiste Zeit im Cache heiß. Wenn zwei Threads dies tun, kämpfen ihre Caches um den Besitz des Speichers, der diese Variable enthält, und viele Zugriffe sind langsamer, wenn das Cache-Kohärenzprotokoll arbeitet, um jeden Kernbesitz der Cache-Zeile zu sichern.

Ironischerweise reduzieren Sperren normalerweise Konflikte. Warum? Denn ohne eine Sperre könnten zwei Threads dasselbe Objekt oder dieselbe Sammlung bearbeiten und viele Konflikte verursachen (z. B. gibt es Warteschlangen ohne Sperren). Sperren neigen dazu, konkurrierende Threads zu deaktivieren, sodass nicht konkurrierende Threads stattdessen ausgeführt werden können. Wenn Thread A eine Sperre enthält und Thread B dieselbe Sperre wünscht, kann die Implementierung stattdessen Thread C ausführen. Wenn Thread C diese Sperre nicht benötigt, können zukünftige Konflikte zwischen Thread A und B für eine Weile vermieden werden. (Dies setzt natürlich voraus, dass andere Threads ausgeführt werden könnten. Es hilft nicht, wenn das System als Ganzes nur dann nützliche Fortschritte erzielen kann, wenn konkurrierende Threads ausgeführt werden.)

David Schwartz
quelle
4
+1 Um dies deutlich zu machen, müssen die beiden Variablen, um die sich zwei Kerne streiten, nicht einmal dieselbe Variable sein, um Konflikte zu verursachen. Sie müssen nur im Speicher in derselben Cache-Zeile gespeichert werden. Das Auffüllen von Strukturen und / oder das Ausrichten von Strukturen am Speicher kann dazu beitragen, diese Form von Konflikten zu vermeiden.
Rob_before_edits
1
@ David bitte helfen Sie, den letzten Absatz Ihrer Antwort genauer zu verstehen
Lerner
4
@Naroji Stellen Sie eine Frage dazu.
David Schwartz
@ DavidSchwartz, bist du ein C-Programmierer?
Pacerier
@ Pacerier C ++ meistens.
David Schwartz
19

Von hier aus :

Ein Konflikt tritt auf, wenn ein Thread auf eine Ressource wartet, die nicht sofort verfügbar ist. Dies verlangsamt die Ausführung Ihres Codes, kann jedoch im Laufe der Zeit behoben werden.

Ein Deadlock tritt auf, wenn ein Thread auf eine Ressource wartet, die ein zweiter Thread gesperrt hat, und der zweite Thread auf eine Ressource wartet, die der erste Thread gesperrt hat. An einem Deadlock können mehr als zwei Threads beteiligt sein. Ein Deadlock löst sich nie von selbst auf. Dies führt häufig dazu, dass die gesamte Anwendung oder der Teil, bei dem der Deadlock auftritt, angehalten wird.

Jon B.
quelle
Dies erklärt auch den Unterschied zwischen Thread Contention und Deadlock
Sankalp
3

Ich denke, es sollte eine Klarstellung des OP zum Hintergrund der Frage geben - ich kann mir 2 Antworten vorstellen (obwohl ich sicher bin, dass es Ergänzungen zu dieser Liste gibt):

  1. Wenn Sie sich auf das allgemeine "Konzept" von Thread-Konflikten beziehen und wie es sich in einer Anwendung präsentieren kann, verweise ich auf die ausführliche Antwort von @ DavidSchwartz oben.

  2. Es gibt auch den Leistungsindikator ".NET CLR-Sperren und -Threads: Gesamtzahl der Inhalte". Wie aus der PerfMon-Beschreibung für diesen Zähler hervorgeht, ist er definiert als:

    Dieser Zähler zeigt an, wie oft Threads in der CLR insgesamt erfolglos versucht haben, eine verwaltete Sperre zu erhalten. Verwaltete Sperren können auf viele Arten erworben werden. durch die Anweisung "lock" in C # oder durch Aufrufen von System.Monitor.Enter oder durch Verwendung des benutzerdefinierten Attributs MethodImplOptions.Synchronized.

... und ich bin sicher, andere für andere Betriebssysteme und Anwendungs-Frameworks.

Dave Black
quelle
2

Du hast 2 Threads. Thread A und Thread B, Sie haben auch Objekt C.

A greift derzeit auf Objekt C zu und hat dieses Objekt gesperrt. B muss auf Objekt C zugreifen, kann dies jedoch erst tun, wenn A die Sperre für Objekt C aufhebt.

Aaron M.
quelle
1

Ein anderes Wort könnte Parallelität sein. Es ist einfach die Idee, dass zwei oder mehr Threads versuchen, dieselbe Ressource zu verwenden.

Mark Wilkins
quelle
1

Für mich ist der Wettbewerb ein Wettbewerb zwischen zwei oder mehr Threads um eine gemeinsam genutzte Ressource. Ressource kann ein Schloss, ein Zähler usw. sein. Wettbewerb bedeutet "wer bekommt es zuerst". Je mehr Threads, desto mehr Streit. Je häufiger auf eine Ressource zugegriffen wird, desto mehr Konflikte treten auf.

Maciej
quelle
1

Stellen Sie sich das folgende Szenario vor. Sie bereiten sich auf die morgige Abschlussprüfung vor und fühlen sich ein wenig hungrig. Also gibst du deinem jüngeren Bruder zehn Dollar und bittest ihn, eine Pizza für dich zu kaufen. In diesem Fall sind Sie der Haupt-Thread und Ihr Bruder ist ein untergeordneter Thread. Sobald Ihre Bestellung eingegangen ist, erledigen Sie und Ihr Bruder gleichzeitig ihre Arbeit (dh Sie studieren und kaufen eine Pizza). Nun müssen wir zwei Fälle berücksichtigen. Zuerst bringt dein Bruder deine Pizza zurück und endet, während du lernst. In diesem Fall können Sie aufhören zu lernen und die Pizza genießen. Zweitens beenden Sie Ihr Studium früh und schlafen (dh Ihr zugewiesener Job für heute - das Studium für die morgige Abschlussprüfung - ist erledigt), bevor die Pizza verfügbar ist. Natürlich kannst du nicht schlafen; Andernfalls haben Sie keine Chance, die Pizza zu essen.

Wie im Beispiel geben die beiden Fälle die Bedeutung von Rivalität an.

snr
quelle
0

Thread-Konflikte werden auch durch E / A-Vorgänge beeinflusst. Beispiel: Wenn ein Thread, der auf das Lesen einer Datei wartet, als Konflikt betrachtet werden kann. Verwenden Sie E / A-Abschlussports als Lösung.

Amilamad
quelle
0

Sperrenkonflikte treten auf, wenn ein Thread versucht, die Sperre für ein Objekt zu erlangen, das bereits von einem anderen Thread * erfasst wurde. Bis das Objekt freigegeben wird, wird der Thread blockiert (mit anderen Worten, er befindet sich im Wartezustand). In einigen Fällen kann dies zu einer sogenannten seriellen Ausführung führen, die sich negativ auf die Anwendung auswirkt.

aus der dotTrace-Dokumentation

AndreyT
quelle