Heim > Artikel > System-Tutorial > Der Master zeigt Ihnen, wie Sie den Ruhezustand und das Aufwecken von Linux-Prozessen einrichten
Einführung | Unter Linux werden Prozesse, die nur auf CPU-Zeit warten, als bereite Prozesse bezeichnet. Sie werden in eine Ausführungswarteschlange gestellt und das Statusflag eines bereiten Prozesses ist TASK_RUNNING. Sobald die Zeitspanne eines laufenden Prozesses erschöpft ist, entzieht der Linux-Kernel-Scheduler dem Prozess die Kontrolle über die CPU und wählt einen geeigneten Prozess aus der Ausführungswarteschlange zur Ausführung aus. |
Natürlich kann ein Prozess auch aktiv die Kontrolle über die CPU freigeben. Die Funktion Schedule() ist eine Planungsfunktion, die von einem Prozess aktiv aufgerufen werden kann, um andere Prozesse so zu planen, dass sie die CPU belegen. Sobald der Prozess, der die CPU aktiv aufgibt, neu geplant wird, um die CPU zu belegen, beginnt er mit der Ausführung an der Stelle, an der er zuletzt aufgehört hat, d. h. er beginnt mit der Ausführung ab der nächsten Codezeile, die Schedule() aufruft.
Manchmal muss ein Prozess warten, bis ein bestimmtes Ereignis eintritt, z. B. die Geräteinitialisierung, der Abschluss eines E/A-Vorgangs oder der Ablauf des Timers. In diesem Fall muss der Prozess aus der Ausführungswarteschlange entfernt und einer Warteschlange hinzugefügt werden. Zu diesem Zeitpunkt wechselt der Prozess in den Ruhezustand.
Einer ist der unterbrechbare Ruhezustand, sein Statusflag ist TASK_INTERRUPTIBLE
;
Der andere ist ein unterbrechungsfreier Ruhezustand und sein Statusflag ist TASK_UNINTERRUPTIBLE. Ein Prozess in einem unterbrechbaren Ruhezustand bleibt so lange im Ruhezustand, bis eine bestimmte Bedingung erfüllt wird. Beispielsweise können das Erzeugen eines Hardware-Interrupts, die Freigabe von Systemressourcen, auf die der Prozess wartet, oder die Übermittlung eines Signals die Bedingungen sein, um den Prozess aufzuwecken. Der ununterbrochene Schlafzustand ähnelt dem unterbrechbaren Schlafzustand, es gibt jedoch eine Ausnahme: Der Prozess, der das Signal an diesen Schlafzustand sendet, kann seinen Zustand nicht ändern, das heißt, er reagiert nicht auf das Signal zum Aufwachen. Der unterbrechungsfreie Ruhezustand wird im Allgemeinen seltener verwendet, ist jedoch in bestimmten Situationen immer noch sehr nützlich. Beispielsweise muss der Prozess warten und kann nicht unterbrochen werden, bis ein bestimmtes Ereignis eintritt.
In modernen Linux-Betriebssystemen wechseln Prozesse im Allgemeinen durch Aufrufen von Schedule() in den Ruhezustand. Der folgende Code wird ausgeführt
zeigt, wie man einen laufenden Prozess in den Ruhezustand versetzt.
Sleeping_task = current;
set_current_state(TASK_INTERRUPTIBLE);
Zeitplan();
func1();
/* Rest des Codes ... */
In der ersten Anweisung speichert das Programm einen Prozessstrukturzeiger „sleeping_task“ und „current“ ist ein Makro, das auf die aktuelle Ausführung zeigt
Prozessstruktur. set_current_state() ändert den Status des Prozesses vom Ausführungsstatus TASK_RUNNING in den Ruhezustand
TASK_INTERRUPTIBLE. Wenn Schedule() von einem Prozess mit dem Status TASK_RUNNING geplant wird, dann plant Schedule() einen anderen Prozess, um die CPU zu belegen. Wenn Schedule() von einem Prozess mit dem Status TASK_INTERRUPTIBLE oder TASK_UNINTERRUPTIBLE geplant wird, gibt es einen zusätzlichen Schritt Wird ausgeführt: Der aktuell ausgeführte Prozess wird aus der Ausführungswarteschlange entfernt, bevor ein anderer Prozess geplant wird, was dazu führt, dass der laufende Prozess in den Ruhezustand wechselt, da er sich nicht mehr in der Ausführungswarteschlange befindet.
Wir können die folgende Funktion verwenden, um den Prozess aufzuwecken, der gerade in den Ruhezustand gegangen ist.
wake_up_process(sleeping_task);
Nach dem Aufruf von wake_up_process() wird der Status des schlafenden Prozesses auf TASK_RUNNING gesetzt und der Scheduler
Es wird zur Ausführungswarteschlange hinzugefügt. Natürlich kann dieser Prozess erst dann in Betrieb genommen werden, wenn er das nächste Mal vom Planer geplant wird.
In fast allen Fällen wird der Prozess in den Ruhezustand versetzt, nachdem bestimmte Bedingungen überprüft und festgestellt wurden, dass die Bedingungen nicht erfüllt sind. Aber manchmal
Der Prozess beginnt jedoch mit dem Ruhezustand, nachdem die Beurteilungsbedingung erfüllt ist. Wenn dies der Fall ist, wird der Prozess auf unbestimmte Zeit in den Ruhezustand versetzt. Wenn im Betriebssystem mehrere Prozesse versuchen, gemeinsam genutzte Daten zu verarbeiten, und das Endergebnis von der Reihenfolge abhängt, in der die Prozesse ausgeführt werden, tritt eine Race-Bedingung auf. Dies ist ein typisches Problem im Betriebssystem. nach oben Das liegt gerade an den Wettbewerbsbedingungen.
Stellen Sie sich vor, es gibt zwei Prozesse A und B. Prozess A verarbeitet eine verknüpfte Liste. Er muss prüfen, ob die verknüpfte Liste leer ist
Die Daten in der Tabelle werden einigen Vorgängen unterzogen, und Prozess B fügt der verknüpften Liste auch Knoten hinzu. Wenn die verknüpfte Liste leer ist, weil keine Daten zum Bearbeiten vorhanden sind, geht Prozess A in den Ruhezustand. Wenn Prozess B der verknüpften Liste einen Knoten hinzufügt, wird Prozess A aktiviert. Der Code lautet wie folgt:
Ein Prozess:
1 spin_lock(&list_lock);
2 if(list_empty(&list_head)) {
3 spin_unlock(&list_lock);
4 set_current_state(TASK_INTERRUPTIBLE);
5 Zeitplan();
6 spin_lock(&list_lock);
7}
8
9 /* Rest des Codes ... */
10 spin_unlock(&list_lock);
B-Prozess:
100 spin_lock(&list_lock);
101 list_add_tail(&list_head, new_node);
102 spin_unlock(&list_lock);
103 wake_up_process(processa_task);
Hier liegt ein Problem vor, wenn Prozess A nach Zeile 3 und vor Zeile 4 ausgeführt wird, Prozess B wird von einem anderen Prozessor geplant
in Dienst gestellt. Innerhalb dieser Zeitspanne hat Prozess B alle seine Anweisungen ausgeführt und versucht daher, Prozess A aufzuwecken. Zu diesem Zeitpunkt ist Prozess A noch nicht in den Ruhezustand eingetreten, sodass der Aufweckvorgang ungültig ist. Danach wird Prozess A weiter ausgeführt. Er geht fälschlicherweise davon aus, dass die verknüpfte Liste zu diesem Zeitpunkt noch leer ist. Daher setzt er seinen Status auf TASK_INTERRUPTIBLE und ruft dann Schedule() auf, um in den Ruhezustand zu wechseln. Da Prozess B den Weckruf verpasst hat, schläft er auf unbestimmte Zeit. Dies ist das Problem des ungültigen Weckens, da Prozess A auch dann noch schläft, wenn die verknüpfte Liste Daten enthält, die verarbeitet werden müssen.
Vor dem Status bot wake_up_process() von Prozess B ursprünglich die Möglichkeit, den Status von Prozess A auf TASK_RUNNING zu setzen. Leider war der Status von Prozess A zu diesem Zeitpunkt noch TASK_RUNNING, sodass wake_up_process() den Status von Prozess A aus dem Ruhezustand änderte Zustand in den laufenden Zustand versetzt. Der Aufwand hatte nicht den gewünschten Effekt. Um dieses Problem zu lösen, muss ein Garantiemechanismus verwendet werden, um die Feststellung, dass die verknüpfte Liste leer ist, und das Setzen des Prozessstatus in den Ruhezustand zu einem integralen Schritt zu machen. Das heißt, die Quelle der Race-Bedingung muss beseitigt werden, damit der wake_up_process ( ) kann die Rolle spielen, einen Prozess aufzuwecken, der sich im Schlafzustand befindet.
Nachdem Sie den Grund gefunden haben, entwerfen Sie die Codestruktur von Prozess A neu, um das Problem des ungültigen Aufweckens im obigen Beispiel zu vermeiden.
Ein Prozess:
1 set_current_state(TASK_INTERRUPTIBLE);
2 spin_lock(&list_lock);
3 if(list_empty(&list_head)) {
4 spin_unlock(&list_lock);
5 Zeitplan();
6 spin_lock(&list_lock);
7}
8 set_current_state(TASK_RUNNING);
9
10 /* Rest des Codes ... */
11 spin_unlock(&list_lock);
Wie Sie sehen können, setzt dieser Code den aktuellen Ausführungsprozessstatus auf TASK_INTERRUPTIBLE, bevor die Bedingungen getestet werden, und setzt sich selbst auf den Status TASK_RUNNING, wenn die verknüpfte Liste nicht leer ist. Wenn sich Prozess B in Prozess A befindet, führen Sie auf diese Weise eine Prozessprüfung durch
Nach dem Aufruf von wake_up_process(), nachdem die verknüpfte Liste leer ist, ändert sich der Status von Prozess A automatisch vom ursprünglichen TASK_INTERRUPTIBLE
Danach wird er zu TASK_RUNNING, selbst wenn der Prozess erneut Schedule() aufruft, da sein aktueller Status TASK_RUNNING ist, er wird immer noch nicht aus der Ausführungswarteschlange entfernt, sodass er nicht versehentlich in den Ruhezustand wechselt, was natürlich das Problem darstellt Ungültiges Aufwecken wird vermieden.
Linux-Kernel-Beispiel
Im Linux-Betriebssystem ist die Stabilität des Kernels von entscheidender Bedeutung, um ungültige Wakeup-Probleme im Linux-Betriebssystemkern zu vermeiden,
Der Linux-Kernel sollte Vorgänge ähnlich den folgenden verwenden, wenn er einen Prozess in den Ruhezustand versetzen muss:
/* ‚q‘ ist die Warteschlange, in der wir schlafen möchten */
DECLARE_WAITQUEUE(wait,current);
add_wait_queue(q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
/* oder TASK_INTERRUPTIBLE */
while(!condition) /* ‚condition‘ ist die Bedingung, auf die gewartet werden soll*/
Zeitplan();
set_current_state(TASK_RUNNING);
remove_wait_queue(q, &wait);
Der obige Vorgang ermöglicht es dem Prozess, sich durch die folgende Reihe von Schritten sicher einer Warteschlange für den Ruhezustand hinzuzufügen: Zuerst anpassen
Verwenden Sie DECLARE_WAITQUEUE (), um ein Warteschlangenelement zu erstellen, rufen Sie dann add_wait_queue() auf, um sich der Warteschlange hinzuzufügen, und setzen Sie den Status des Prozesses auf TASK_INTERRUPTIBLE oder TASK_INTERRUPTIBLE. Dann prüft die Schleife, ob die Bedingung wahr ist: Wenn ja, besteht kein Grund zum Schlafen, wenn die Bedingung nicht wahr ist, wird Schedule() aufgerufen. Wenn die vom Prozess überprüften Bedingungen erfüllt sind, setzt sich der Prozess auf TASK_RUNNING und ruft „remove_wait_queue()“ auf, um sich aus der Warteschlange zu entfernen.
Wie Sie oben sehen können, setzt der Linux-Kernel-Code-Betreuer auch den Status des Prozesses in den Ruhezustand, bevor der Prozess die Bedingungen überprüft,
Anschließend prüft die Schleife die Bedingung. Wenn die Bedingung erfüllt ist, bevor der Prozess in den Ruhezustand übergeht, wird die Schleife beendet und set_current_state() verwendet, um ihren Zustand auf „Bereit“ zu setzen. Dadurch wird auch sichergestellt, dass der Prozess nicht dazu neigt, versehentlich in den Ruhezustand zu wechseln verursacht keinen Fehler. Ungültiges Weckproblem.
Lassen Sie uns anhand eines Beispiels im Linux-Kernel sehen, wie der Linux-Kernel ungültigen Ruhezustand vermeidet. Dieser Code stammt aus dem Linux2.6-Kernel (linux-2.6.11/kernel/sched.c: 4254):
4253 /* Warten Sie auf kthread_stop */
4254 set_current_state(TASK_INTERRUPTIBLE);
4255 while (!kthread_should_stop()) {
4256 Zeitplan();
4257 set_current_state(TASK_INTERRUPTIBLE);
4258 }
4259 __set_current_state(TASK_RUNNING);
4260 gibt 0;
zurück
Die oben genannten Codes gehören zum Migrationsdienst-Thread migration_thread. Dieser Thread überprüft ständig kthread_should_stop(),
Die Schleife kann erst verlassen werden, wenn kthread_should_stop() 1 zurückgibt, was bedeutet, dass der Prozess so lange ruht, wie kthread_should_stop() 0 zurückgibt. Aus dem Code können wir ersehen, dass die Prüfung kthread_should_stop() tatsächlich ausgeführt wird, nachdem der Prozessstatus auf TASK_INTERRUPTIBLE gesetzt wurde. Wenn daher ein anderer Prozess versucht, ihn nach der Bedingungsprüfung, aber vor dem Zeitplan() aufzuwecken, wird der Aufweckvorgang des Prozesses nicht ungültig.
Durch die obige Diskussion können wir feststellen, dass der Schlüssel zur Vermeidung eines ungültigen Aufweckens des Prozesses unter Linux darin besteht, den Prozess aufzuwecken, bevor der Prozess die Bedingung überprüft
Der Status wird auf TASK_INTERRUPTIBLE oder TASK_UNINTERRUPTIBLE gesetzt, und wenn die überprüften Bedingungen erfüllt sind, sollte dies der Fall sein
Setzen Sie den Status auf TASK_RUNNING zurück. Unabhängig davon, ob die Wartebedingungen des Prozesses erfüllt sind oder nicht, wechselt der Prozess auf diese Weise nicht versehentlich in den Ruhezustand, da er aus der Bereitschaftswarteschlange entfernt wird, wodurch das Problem eines ungültigen Aufweckens vermieden wird.
Das obige ist der detaillierte Inhalt vonDer Master zeigt Ihnen, wie Sie den Ruhezustand und das Aufwecken von Linux-Prozessen einrichten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!