Heim > Artikel > Backend-Entwicklung > Linux – Thread-Synchronisation und gegenseitiger Ausschluss
1. Mutex-Mutex
Synchronisierung: Geordneter Zugriff auf Ressourcen. Gegenseitiger Ausschluss: Es wird immer nur eines ausgeführt. Bei Multithread-Programmen treten jedoch häufig Zugriffskonflikte auf. Die Lösung besteht darin, einen Mutex (Mutex, MutualExclusive Lock) einzuführen und die Sperre zu erhalten Führen Sie die Operation „Lesen-Ändern-Schreiben“ aus und geben Sie dann die Sperre für andere Threads frei, die die Sperre nicht erhalten haben. Auf diese Weise kann die dreistufige Operation „Lesen-Ändern-Schreiben“ ausgeführt werden. write“ bildet eine atomare Operation. Entweder führen Sie alle oder keines aus, sie werden während der Ausführung nicht unterbrochen und diese Operation wird nicht parallel auf anderen Prozessoren ausgeführt.
Mutex-Sperren werden durch Variablen vom Typ pthread_mutex_t dargestellt. Mit pthread_mutex_init initialisiert und mit hread_destroy() zerstört. Gibt bei Erfolg 0 und bei Misserfolg eine Fehlernummer zurück. . Wenn die Mutex-Variable statisch zugewiesen ist (globale Variable oder statische Variable), kann sie auch mit der Makrodefinition PTHREAD_MUTEX_INITIALIZER initialisiert werden, was der Initialisierung mit pthread_mutex_init entspricht und der Parameter attr NULL ist
Ein Thread kann pthread_mutex_lock aufrufen, um die zu erhalten Mutex. Wenn zu diesem Zeitpunkt ein anderer Thread pthread_mutex_lock aufgerufen hat, um den Mutex zu erhalten, muss der aktuelle Thread warten, bis ein anderer Thread pthread_mutex_unlock aufruft, um den Mutex freizugeben, und der aktuelle Thread aktiviert wird, bevor er den Mutex erhalten und die Ausführung fortsetzen kann . Das heißt, wenn ein Thread den Mutex sperrt, aber nicht entsperrt und ein anderer Thread den Mutex erhalten möchte, muss er auflegen und warten, bis der gesperrte Thread den Mutex entsperrt und den Mutex freigibt, und dann wird der Thread aktiviert und kann Erhalten Sie den Mutex.
Wenn ein Thread die Sperre erhalten möchte, aber nicht hängen und warten möchte, kann er pthread_mutex_trylock aufrufen. Wenn der Mutex von einem anderen Thread erfasst wurde, schlägt diese Funktion fehl und gibt EBUSY zurück, ohne den Thread zu verursachen hängen und warten.
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<pthread.h> 4 static int g_count=0; 5 void * addWrite(void * arg) 6 { 7 int count=0; 8 int value=0; 9 while(count++ <5000) 10 { 11 value=g_count; 12 printf("g_count is %d\n",g_count); 13 g_count=value+1; 14 } 15 } 16 int main() 17 { 18 pthread_t id1; 19 pthread_t id2; 20 int ret=pthread_create(&id1,NULL,addWrite,NULL); 21 int res=pthread_create(&id2,NULL,addWrite,NULL); 22 pthread_join(id1,NULL); 23 pthread_join(id2,NULL);
Wir erstellen zwei Threads, von denen jeder g_count um das 5000-fache erhöht. Normalerweise sollte der Endzähler 10000 betragen, aber tatsächlich ist das Ergebnis jedes Mal anders, wenn das Programm ausgeführt wird. Manchmal erreicht es 5000 count erreicht mehr als 6.000, aber nach dem Hinzufügen der Sperre fügen Sie pthread_mutex_init in der fünften Zeile hinzu (wie unten gezeigt)
Ergebnis:
Nach dem Hinzufügen der Sperre werden 10000 ausgegeben
2. Implementierungsprinzip von Sperren und Entsperren
Um die Mutex-Sperroperation zu realisieren, bieten die meisten Architekturen Swap- oder Exchange-Anweisungen Die Anweisung besteht darin, Daten zwischen dem Register und der Speichereinheit auszutauschen. Die Atomizität ist auch auf einer Multiprozessorplattform gewährleistet ausgeführt, wenn ein anderer Die Swap-Anweisungen des Prozessors können nur auf Buszyklen warten. Dies wird im folgenden Pseudocode dargestellt. Der Sperrfreigabevorgang beim Entsperren wird ebenfalls mit nur einer Anweisung implementiert, um seine Atomizität sicherzustellen.
3. Deadlock
・Wenn derselbe Thread beim zweiten Aufruf die Sperre zweimal aufruft, hängt der Thread im Allgemeinen auf, da die Sperre bereits belegt ist und warten, bis andere Threads die Sperre aufheben. Der Thread wird jedoch angehalten, ohne dass er die Möglichkeit hat, die Sperre aufzuheben. Dies wird als Deadlock bezeichnet. Eine weitere typische Deadlock-Situation ist folgende: Thread A erhält Sperre 1 und Thread B erhält Sperre 2. Zu diesem Zeitpunkt ruft Thread A Sperre auf, um zu versuchen, Sperre 2 zu erhalten. Daher muss er hängen bleiben und warten, bis Thread B freigegeben wird Sperre 2 und dies Zu diesem Zeitpunkt ruft Thread B auch Sperre auf, um zu versuchen, Sperre 1 zu erhalten. Daher muss er warten, bis Thread A Sperre 1 freigibt, sodass sich beide Threads A und B für immer in einem angehaltenen Zustand befinden.
Bedingungen für die Bildung eines Deadlocks
① Bedingung für gegenseitigen Ausschluss: Eine Ressource kann jeweils nur von einem Thread verwendet werden.
②. Anforderungs- und Aufbewahrungsbedingungen: Wenn ein Prozess aufgrund der Anforderung von Ressourcen blockiert wird, behält er die erhaltenen Ressourcen bei.
③ Nichtentzugsbedingungen: Ressourcen, die ein Prozess erhalten hat, können nicht gewaltsam entzogen werden, bevor sie aufgebraucht sind.
④Zyklische Wartebedingung: Zwischen mehreren Prozessen wird eine direkte zyklische Warteressourcenbeziehung gebildet.
Wenn mehr Threads und mehr Sperren beteiligt sind, ist es wahrscheinlicher, dass es zu einem Deadlock-Problem kommt. Wenn Sie ein Programm schreiben, sollten Sie versuchen, das gleichzeitige Erlangen mehrerer Sperren zu vermeiden. Wenn dies erforderlich ist, gilt ein Grundsatz: Wenn alle Threads mehrere Sperren benötigen, müssen sie derselben Reihenfolge folgen (die häufigste ist). durch die Adressreihenfolge der Mutex-Variablen) Wenn die Sperre erhalten wird, tritt kein Deadlock auf. Wenn beispielsweise Lock 1, Lock 2 und Lock 3 in einem Programm verwendet werden und die Adressen ihrer entsprechenden Mutex-Variablen Lock 1
Das Obige ist der Inhalt der Linux-Thread-Synchronisierung und des gegenseitigen Ausschlusses. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn).