Heim >System-Tutorial >LINUX >Linux-Prozesse einschlafen und aufwecken: Machen Sie Ihr System energiesparender und effizienter

Linux-Prozesse einschlafen und aufwecken: Machen Sie Ihr System energiesparender und effizienter

PHPz
PHPznach vorne
2024-02-14 10:36:121247Durchsuche

Linux-System ist ein Betriebssystem, das die gleichzeitige Ausführung mehrerer Aufgaben unterstützt. Es kann mehrere Prozesse gleichzeitig ausführen und dadurch die Systemauslastung und -effizienz verbessern. Allerdings müssen nicht alle Prozesse ständig Prozessorressourcen belegen. Einige Prozesse können unter bestimmten Bedingungen den Prozessor vorübergehend aufgeben, in den Ruhezustand wechseln, auf die Erfüllung der Bedingungen warten, dann aufwachen und mit der Ausführung fortfahren. Dies hat den Vorteil, dass Prozessorressourcen eingespart werden können und dass andere Prozesse, die ausgeführt werden müssen, mehr Möglichkeiten haben. Außerdem können der Stromverbrauch und die Wärmeentwicklung des Systems reduziert und die Stabilität und Lebensdauer des Systems verbessert werden. In diesem Artikel werden die Schlaf- und Weckmethoden von Prozessen in Linux-Systemen vorgestellt, einschließlich der Schlafgründe, Schlaftypen, Schlaffunktionen, Weckfunktionen und Weckmechanismen des Prozesses.

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 freiwillig aufgibt, neu geplant wird, um die CPU zu belegen, beginnt er mit der Ausführung an der Stelle, an der er zuletzt gestoppt wurde, 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.

Linux-Prozesse einschlafen und aufwecken: Machen Sie Ihr System energiesparender und effizienter

Klassifizierung des Prozessschlafstatus in Linux

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);
schedule();
func1();
/* Rest of the code ... */

In der ersten Anweisung speichert das Programm einen Prozessstrukturzeiger Sleeping_task, 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 im Status TASK_RUNNING geplant wird, dann plant Schedule() einen anderen Prozess, um die CPU zu belegen. Wenn Schedule() von einem Prozess im Status TASK_INTERRUPTIBLE oder TASK_UNINTERRUPTIBLE geplant wird, gibt es einen zusätzlichen Schritt dazu 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.

Ungültiges Wecken

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. Wenn sie nicht leer ist, wird der Link gelöscht. 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 schedule();
6 spin_lock(&list_lock);
7 }
8
9 /* Rest of the code ... */
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);

这里会出现一个问题,假如当A进程执行到第3行后第4行前的时候,B进程被另外一个处理器调度
投 入运行。在这个时间片内,B进程执行完了它所有的指令,因此它试图唤醒A进程,而此时的A进程还没有进入睡眠,所以唤醒操作无效。在这之后,A 进程继续执行,它会错误地认为这个时候链表仍然是空的,于是将自己的状态设置为TASK_INTERRUPTIBLE然后调用schedule()进入睡 眠。由于错过了B进程唤醒,它将会无限期的睡眠下去,这就是无效唤醒问题,因为即使链表中有数据需要处理,A 进程也还是睡眠了。

避免无效唤醒

如何避免无效唤醒问题呢?我们发现无效唤醒主要发生在检查条件之后和进程状态被设置为睡眠状
态之前, 本来B进程的wake_up_process()提供了一次将A进程状态置为TASK_RUNNING 的机会,可惜这个时候A进程的状态仍然是TASK_RUNNING,所以wake_up_process()将A进程状态从睡眠状态转变为运行状态的努力 没有起到预期的作用。要解决这个问题,必须使用一种保障机制使得判断链表为空和设置进程状态为睡眠状态成为一个不可分割的步骤才行,也就是必须消除竞争条 件产生的根源,这样在这之后出现的wake_up_process ()就可以起到唤醒状态是睡眠状态的进程的作用了。
找到了原因后,重新设计一下A进程的代码结构,就可以避免上面例子中的无效唤醒问题了。
A进程:

1 set_current_state(TASK_INTERRUPTIBLE);
2 spin_lock(&list_lock);
3 if(list_empty(&list_head)) {
4 spin_unlock(&list_lock);
5 schedule();
6 spin_lock(&list_lock);
7 }
8 set_current_state(TASK_RUNNING);
9
10 /* Rest of the code ... */
11 spin_unlock(&list_lock);

可以看到,这段代码在测试条件之前就将当前执行进程状态转设置成TASK_INTERRUPTIBLE了,并且在链表不为空的情况下又将自己置为TASK_RUNNING状态。这样一来如果B进程在A进程进程检查
了链表为空以后调用wake_up_process(),那么A进程的状态就会自动由原来TASK_INTERRUPTIBLE
变成TASK_RUNNING,此后即使进程又调用了schedule(),由于它现在的状态是TASK_RUNNING,所以仍然不会被从运行队列中移出,因而不会错误的进入睡眠,当然也就避免了无效唤醒问题。

Linux内核的例子

在Linux操作系统中,内核的稳定性至关重要,为了避免在Linux操作系统内核中出现无效唤醒问题,
Linux内核在需要进程睡眠的时候应该使用类似如下的操作:
/* ‘q’是我们希望睡眠的等待队列 /
DECLARE_WAITQUEUE(wait,current);
add_wait_queue(q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
/
或TASK_INTERRUPTIBLE /
while(!condition) /
‘condition’ 是等待的条件*/
schedule();
set_current_state(TASK_RUNNING);
remove_wait_queue(q, &wait);
上面的操作,使得进程通过下面的一系列步骤安全地将自己加入到一个等待队列中进行睡眠:首先调
用DECLARE_WAITQUEUE ()创建一个等待队列的项,然后调用add_wait_queue()把自己加入到等待队列中,并且将进程的状态设置为 TASK_INTERRUPTIBLE 或者TASK_INTERRUPTIBLE。然后循环检查条件是否为真:如果是的话就没有必要睡眠,如果条件不为真,就调用schedule()。当进程 检查的条件满足后,进程又将自己设置为TASK_RUNNING 并调用remove_wait_queue()将自己移出等待队列。
从上面可以看到,Linux的内核代码维护者也是在进程检查条件之前就设置进程的状态为睡眠状态,
然后才循环检查条件。如果在进程开始睡眠之前条件就已经达成了,那么循环会退出并用set_current_state()将自己的状态设置为就绪,这样同样保证了进程不会存在错误的进入睡眠的倾向,当然也就不会导致出现无效唤醒问题。
下面让我们用linux 内核中的实例来看看Linux 内核是如何避免无效睡眠的,这段代码出自Linux2.6的内核(linux-2.6.11/kernel/sched.c: 4254):
4253 /* Wait for kthread_stop */
4254 set_current_state(TASK_INTERRUPTIBLE);
4255 while (!kthread_should_stop()) {
4256 schedule();
4257 set_current_state(TASK_INTERRUPTIBLE);
4258 }
4259 __set_current_state(TASK_RUNNING);
4260 return 0;
上面的这些代码属于迁移服务线程migration_thread,这个线程不断地检查kthread_should_stop(),
直 到kthread_should_stop()返回1它才可以退出循环,也就是说只要kthread_should_stop()返回0该进程就会一直睡 眠。从代码中我们可以看出,检查kthread_should_stop()确实是在进程的状态被置为TASK_INTERRUPTIBLE后才开始执行 的。因此,如果在条件检查之后但是在schedule()之前有其他进程试图唤醒它,那么该进程的唤醒操作不会失效。

In diesem Artikel werden die Schlaf- und Weckmethoden von Prozessen in Linux-Systemen vorgestellt, einschließlich Schlafgrund, Schlaftyp, Schlaffunktion, Weckfunktion und Weckmechanismus des Prozesses. Durch das Verständnis und die Beherrschung dieses Wissens können wir die Prozesse im Linux-System besser verwalten und steuern, wodurch das System energiesparender und effizienter läuft. Natürlich gibt es viele Details und Techniken für Einschlaf- und Aufwachprozesse in Linux-Systemen, die wir weiter lernen und üben müssen

Das obige ist der detaillierte Inhalt vonLinux-Prozesse einschlafen und aufwecken: Machen Sie Ihr System energiesparender und effizienter. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen