Synchronisation ist die Interaktion zwischen Prozessen sowie zwischen Prozessen und Systemressourcen. Da der Linux-Kernel Multitasking verwendet, muss es einen Synchronisationsmechanismus zwischen mehreren Prozessen geben, um die Koordination sicherzustellen.
Es gibt viele Synchronisierungsmechanismen im Linux-Kernel. Heute konzentrieren wir uns auf die asynchronen und synchronen Mechanismen im Kernel und konzentrieren uns dabei auf den asynchronen Mechanismus im Kernel. Der asynchrone Mechanismus im Kernel ist in zwei Typen unterteilt: Der eine ist der Synchronisationsmechanismus der Anwendungsschicht, dh die Kommunikation zwischen Threads der Anwendungsschicht, der andere ist der Synchronisationsmechanismus des Kernels.
Wenn ein Thread in den Kernel-Status wechselt, kann er direkt mit dem Kernel kommunizieren. Es gibt zwei Threads im Kernel: Einer ist Thread A. Nachdem er in den Kernel-Status eingetreten ist, kommuniziert er direkt mit dem Kernel und teilt ihm mit, was zu tun ist. Wenn er abgeschlossen ist, benachrichtigt er den Kernel. (Wir nennen diese Operation semi) Wenn ein Thread in den Kernel-Status eintritt, kommuniziert er zunächst einmal mit dem Kernel und kann dann direkt ausgeführt werden.
Der Synchronisationsmechanismus im Kernel ist im Wesentlichen ein Kommunikationsmechanismus zwischen Threads, und die Kommunikation zwischen ihnen wird durch den Synchronisationsmechanismus erreicht.
Um die Korrektheit und Konsistenz des Systems sicherzustellen, verwendet der Linux-Kernel Blockierungswarteschlangen, um die Kommunikation zwischen Prozessen während der Kommunikation zwischen Prozessen abzuwickeln. Eine blockierende Warteschlange bedeutet, dass beim Senden einer Nachricht ein Element in der Nachrichtenwarteschlange erstellt wird, aber nicht alle Nachrichten gesendet werden. Erst wenn die Warteschlange für eine bestimmte Nachricht voll ist, wird sie gesendet. Befindet sich keine Nachricht in der Warteschlange des Empfängers, wird die Benachrichtigung empfangen. Befindet sich eine Nachricht in der Warteschlange des Empfängers, wird keine Benachrichtigung empfangen.
Im Kernel ist die Blockierungswarteschlange abstrahiert, d. h. wenn ein Prozess eine Nachricht sendet, wird diese blockiert. Daher ist die Blockierungswarteschlange eigentlich ein Synchronisationsmechanismus. Die Blockierungswarteschlange erstellt über eine bestimmte Funktion ein neues Objekt, das einen Warteschlangenzeiger (Push/Pop) enthält. Wenn die Warteschlange voll ist, verwendet das System das Objekt, auf das der Warteschlangenzeiger zeigt, als Thread des ersten Prozesses, der eine Benachrichtigung ausgibt. Das heißt, der Prozess wird benachrichtigt, bevor er seine Aufgaben weiter ausführen kann.
Semaphoren können zum Senden oder Empfangen von Nachrichten verwendet werden. Wenn ein Prozess ein Semaphor besitzt, bedeutet das, dass er bereits ein eigenes Semaphor besitzt, bei dem es sich um eine eigene private Variable handelt. Diese private Variable kann nicht von anderen Prozessen abgerufen werden. Semaphore werden verwendet, um die Anzahl der Semaphore darzustellen, die einem Prozess gehören. Wenn dieser Prozess der Besitzer des Semaphors ist, kann er Nachrichten an andere Prozesse senden. Diese private Variable darf nur von diesem Prozess selbst verwendet werden und kann nicht auf die Prozesse anderer Prozesse übertragen werden.
Wenn ein Thread über ein eigenes Semaphor verfügt, kann er über gemeinsam genutzte Variablen mit anderen Threads kommunizieren. Gemeinsam genutzte Variablen werden auch in anderen Threads verwendet, und andere Threads verwenden gemeinsam genutzte Variablen, um mit sich selbst zu kommunizieren.
Mutex ist hauptsächlich für Systemressourcen gedacht. Mutexe im Linux-Kernel können in zwei Typen unterteilt werden: gemeinsam genutzte Ressourcen und globale Mutex-Ressourcen.
Gemeinsame Ressourcen werden von Prozessen gemeinsam genutzt. Wenn ein Prozess beispielsweise mehrere Threads hat, kann jeder Thread auf diesen gemeinsam genutzten Speicherbereich zugreifen. Globale, sich gegenseitig ausschließende Ressourcen bedeuten, dass Prozesse und Threads nur auf den globalen Speicherbereich zugreifen können, in dem sie sich befinden. In einem System können Mutexe verwendet werden, um die gleichzeitige Ausführung mehrerer Prozesse im Speicher zu ermöglichen. Wenn Sie jedoch die gleichzeitige Ausführung mehrerer Prozesse implementieren möchten, müssen Sie einen Synchronisierungsmechanismus verwenden, um sicherzustellen, dass alle Prozesse im selben Speicher ausgeführt werden können. Mithilfe eines Mutex kann ein Prozess nur auf den globalen Speicherbereich zugreifen, in dem er sich befindet, nicht jedoch auf andere Speicherbereiche. Ein Mutex hat jedoch einen großen Vorteil, nämlich dass es zu keiner Prozessblockierung kommt.
Das Aufkommen von Nachrichtenwarteschlangen hat die Kommunikation zwischen Prozessen erheblich erweitert. Im Kernel gibt es zusätzlich zum Synchronisationsmechanismus einen weiteren asynchronen Mechanismus, nämlich die Nachrichtenwarteschlange. Wir alle wissen, dass der Linux-Kernel Nachrichtenwarteschlangen unterstützt. Obwohl der Kernel detaillierte Informationen zu Nachrichtenwarteschlangen enthält, müssen wir dennoch mit der Anwendungsschicht beginnen, um Nachrichtenwarteschlangen zu verstehen, da der Kernel keine Nachrichtenwarteschlangen im Benutzermodus unterstützt.
Lassen Sie uns zunächst verstehen, was eine Nachrichtenwarteschlange ist.
Die Nachrichtenwarteschlange ist eine spezielle Warteschlange, die die Synchronisierungsanforderungen zwischen mehreren Anwendungsthreads erfüllen kann. Nachrichtenwarteschlangen werden verwendet, um eine asynchrone Kommunikation zwischen Anwendungen und anderen Prozessen oder Threads bereitzustellen. Wenn wir asynchron kommunizieren müssen, können wir dies über eine Nachrichtenwarteschlange tun. Wenn wir beispielsweise die Funktion clear() aufrufen, können wir direkt eine registrierte Nachrichtenwarteschlange verwenden.
Wie erstellt man also eine Nachrichtenwarteschlange? Wenn wir ext2.json verwenden, können wir mit dem Semaphore-Befehl in JAR.json.clear() eine Nachrichtenwarteschlange erstellen.
Im Shared Memory verwenden wir Shared Locks, aber da Shared Locks den Speicher mit einem bestimmten Prozess teilen, müssen Sie eine Shared Lock von anderen Prozessen anfordern, wenn Sie sie erwerben möchten.
Wie im obigen Beispiel greifen wir über das Schlüsselwort volatile auf den gemeinsamen Speicher zu. Zu diesem Zeitpunkt stellen Sie keine Anfragen von anderen Prozessen. Wenn Sie also diese gemeinsame Sperre erhalten möchten, müssen Sie nur Anfragen von anderen Prozessen anfordern. Dadurch wird eine Konkurrenz zwischen den beiden Prozessen vermieden und eine Datensynchronisation erreicht.
Da eine gemeinsame Sperre den Speicher mit einem Prozess teilt, müssen Sie den Prozess auffordern, auf seine Adresse zuzugreifen. Die einfachste Lösung für diese Situation ist die Verwendung eines Thread-Pools.
Im Thread-Pool gibt es ein Objekt namens „Byte“, bei dem es sich auch um eine gemeinsam genutzte Sperre handelt. Wenn Sie diese Sperre erhalten möchten, müssen Sie lediglich eine Anfrage an das Byte-Objekt senden. Zu diesem Zeitpunkt sendet das Byte-Objekt Ihre Anfrage an die Warteschlange des Threads. Wenn der Thread die Anfrage empfängt, sendet er eine Antwortnachricht an Sie zurück.
Thread-Pool ist ein sehr gutes Thread-Management-Tool. Es ermöglicht die gleichzeitige Ausführung mehrerer Threads und kann außerdem Deadlocks und Konflikte zwischen Threads reduzieren. Eine seiner wichtigsten Eigenschaften besteht darin, dass es den Systemspeicher effektiv nutzen kann, um die Effizienz zu verbessern.
Die Verwendung von Thread-Pools ist sehr einfach. Ordnen Sie einfach die auszuführenden Aufgaben den entsprechenden Thread-Pools zu. Wenn die auszuführende Aufgabe dem entsprechenden Thread-Pool zugewiesen ist, kann sie ausgeführt werden. Die Verwendung eines Thread-Pools bringt uns viele Vorteile:
Zwei Synchronisationsmechanismen werden oben vorgestellt. Schauen wir uns also den Synchronisationsmechanismus im Kernel-Status an. Es gibt vier Synchronisierungsmethoden im Kernel-Status:
Durch die obige Analyse verstehen wir, dass die Synchronisierung ein komplexes Problem ist. Wie wird die Synchronisierung im Kernel-Status abgeschlossen?
Zuallererst gibt es im Kernel-Status drei Prozesse: Diese drei Prozesse können gegenseitig auf die Ressourcen zugreifen und sich auch synchronisieren, wenn Ressourcen von anderen Prozessen angefordert werden.
Wenn ein Prozess blockiert ist, entfernen alle seine untergeordneten Prozesse einen untergeordneten Prozess (oder einen anderen untergeordneten Prozess) aus der Warteschlange und fügen ihn der blockierenden Warteschlange hinzu. Wenn alle untergeordneten Prozesse blockiert sind, befinden sich keine untergeordneten Prozesse in der Blockierungswarteschlange. Zu diesem Zeitpunkt fügen andere untergeordnete Prozesse in der Warteschlange den aktuellen Thread zur Warteschlange hinzu. Diese drei Prozesse beeinflussen sich während des Wartevorgangs nicht gegenseitig. Die drei Threads können sich mit anderen Threads synchronisieren, indem sie ihre eigenen Prioritäten festlegen.
Das obige ist der detaillierte Inhalt vonAls Embedded-Entwicklungsingenieur müssen Sie den Synchronisierungsmechanismus des Linux-Kernels kennen.. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!