Linux進程的睡眠與喚醒:讓你的系統更節能更有效率
Linux系統是一種支援多任務並發執行的作業系統,它可以同時運行多個進程,從而提高系統的使用率和效率。但是,並不是所有的行程都需要一直佔用處理器資源,有些行程在某些條件下可以暫時放棄處理器,進入睡眠狀態,等待條件滿足後再被喚醒,繼續執行。這樣做的好處是,可以節省處理器資源,讓其他需要執行的進程得到更多的機會,同時也能降低系統的功耗和發熱,提高系統的穩定性和壽命。本文將介紹Linux系統中進程的睡眠和喚醒的方法,包括進程的睡眠原因、睡眠類型、睡眠函數、喚醒函數和喚醒機制等面向。
當然,一個行程也可以主動釋放CPU的控制權。函數 schedule()是一個調度函數,它可以被一個進程主動調用,從而調度其它進程佔用CPU。一旦這個主動放棄CPU的程序被重新調度佔用 CPU,那麼它將從上次停止執行的位置開始執行,也就是說它將從呼叫schedule()的下一行程式碼開始執行。
有時候,進程需要等待直到某個特定的事件發生,例如裝置初始化完成、I/O 操作完成或計時器到時等。在這種情況下,進程則必須從運行佇列移出,加入到一個等待佇列中,這個時候進程就進入了睡眠狀態。

Linux 中的進程睡眠狀態分類
#一種是可中斷的睡眠狀態,其狀態標誌位元TASK_INTERRUPTIBLE;
另一種是不可中斷 的睡眠狀態,其狀態標誌位元為TASK_UNINTERRUPTIBLE。可中斷的睡眠狀態的進程會睡眠直到某個條件變成真,比如說產生一個硬體中斷、釋放 進程正在等待的系統資源或是傳遞一個訊號都可以是喚醒進程的條件。不可中斷睡眠狀態與可中斷睡眠狀態類似,但是它有一個例外,那就是把訊號傳遞到這種睡眠 狀態的進程不能改變它的狀態,也就是說它不回應訊號的喚醒。不可中斷睡眠狀態一般較少用到,但在某些特定情況下這種狀態還是很有用的,比如說:進程必須等 待,不能被中斷,直到某個特定的事件發生。
在現代的Linux作業系統中,進程一般都是用呼叫schedule()的方法進入睡眠狀態的,下面的程式碼演
示如何讓正在運行的進程進入睡眠狀態。
sleeping_task = current; set_current_state(TASK_INTERRUPTIBLE); schedule(); func1(); /* Rest of the code ... */
在第一個語句中,程式儲存了一份進程結構指標sleeping_task,current 是一個宏,它指向正在執行
的進程結構。 set_current_state()將該行程的狀態從執行狀態TASK_RUNNING 變成睡眠狀態
TASK_INTERRUPTIBLE。如果schedule()是被一個狀態為TASK_RUNNING 的進程調度,那麼schedule()將調度另一個進程佔用CPU;如果schedule()是被一個狀態為TASK_INTERRUPTIBLE 或TASK_UNINTERRUPTIBLE 的進程調度,那麼還有一個附加的步驟將被執行:目前執行的進程在另一個進程被調度之前會被從運行隊列中移出,這將導致正在運行的進程進入睡眠,因為它已經不在運行隊列中了。
我們可以使用下面的這個函數將剛才那個進入睡眠的進程喚醒。
wake_up_process(sleeping_task);
在呼叫了wake_up_process()以後,這個睡眠行程的狀態會被設定為TASK_RUNNING,而且調度器
會把它加入到運行隊列中去。當然,這個進程只有在下次被調度器調度到的時候才能真正投入運作。
無效喚醒
幾乎在所有的情況下,進程都會在檢查了某些條件之後,發現條件不滿足才進入睡眠。可是有的時候
進程卻會在 判定條件為真後開始睡眠,如果這樣的話進程就會無限期地休眠下去,這就是所謂的無效喚醒問題。在作業系統中,當多個進程都企圖對共享資料進行某種處理,而最後的結果又取決於進程運行的順序時,就會發生競爭條件,這是作業系統中一個典型的問題,無效喚醒恰恰就是由於競爭條件導致的。
設想有兩個進程A 和B,A 進程正在處理一個鍊錶,它需要檢查這個鍊錶是否為空,如果不空就對鏈
表裡面的資料進行一些操作,同時B進程也正在往這個鍊錶加入節點。當這個鍊錶是空的時候,由於無資料可操作,這時A進程就進入睡眠,當B進程向鍊錶裡面添加了節點之後它就喚醒A 進程,其程式碼如下:
A進程:
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進程:
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()之前有其他进程试图唤醒它,那么该进程的唤醒操作不会失效。
本文介紹了Linux系統中進程的睡眠和喚醒的方法,包括進程的睡眠原因、睡眠類型、睡眠函數、喚醒函數和喚醒機制等面向。透過了解和掌握這些知識,我們可以更好地管理和控制Linux系統中的進程,讓系統運作得更節能更有效率。當然,Linux系統中進程的睡眠和喚醒還有很多細節和技巧,需要我們不斷學習和實踐
以上是Linux進程的睡眠與喚醒:讓你的系統更節能更有效率的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Linux系統管理員的主要任務包括系統監控與性能調優、用戶管理、軟件包管理、安全管理與備份、故障排查與解決、性能優化與最佳實踐。 1.使用top、htop等工具監控系統性能,並進行調優。 2.通過useradd等命令管理用戶賬戶和權限。 3.利用apt、yum管理軟件包,確保系統更新和安全。 4.配置防火牆、監控日誌、進行數據備份以確保系統安全。 5.通過日誌分析和工具使用進行故障排查和解決。 6.優化內核參數和應用配置,遵循最佳實踐提升系統性能和穩定性。

學習Linux並不難。 1.Linux是一個開源操作系統,基於Unix,廣泛應用於服務器、嵌入式系統和個人電腦。 2.理解文件系統和權限管理是關鍵,文件系統是層次化的,權限包括讀、寫和執行。 3.包管理系統如apt和dnf使得軟件管理方便。 4.進程管理通過ps和top命令實現。 5.從基本命令如mkdir、cd、touch和nano開始學習,再嘗試高級用法如shell腳本和文本處理。 6.常見錯誤如權限問題可以通過sudo和chmod解決。 7.性能優化建議包括使用htop監控資源、清理不必要文件和使用sy

Linux管理員的平均年薪在美國為75,000至95,000美元,歐洲為40,000至60,000歐元。提升薪資可以通過:1.持續學習新技術,如雲計算和容器技術;2.積累項目經驗並建立Portfolio;3.建立職業網絡,拓展人脈。

Linux的主要用途包括:1.服務器操作系統,2.嵌入式系統,3.桌面操作系統,4.開發和測試環境。 Linux在這些領域表現出色,提供了穩定性、安全性和高效的開發工具。

互聯網運行不依賴單一操作系統,但Linux在其中扮演重要角色。 Linux廣泛應用於服務器和網絡設備,因其穩定性、安全性和可擴展性受歡迎。

Linux操作系統的核心是其命令行界面,通過命令行可以執行各種操作。 1.文件和目錄操作使用ls、cd、mkdir、rm等命令管理文件和目錄。 2.用戶和權限管理通過useradd、passwd、chmod等命令確保系統安全和資源分配。 3.進程管理使用ps、kill等命令監控和控制系統進程。 4.網絡操作包括ping、ifconfig、ssh等命令配置和管理網絡連接。 5.系統監控和維護通過top、df、du等命令了解系統運行狀態和資源使用情況。

介紹 Linux是一個強大的操作系統,由於其靈活性和效率,開發人員,系統管理員和電源用戶都喜歡。但是,經常使用長而復雜的命令可能是乏味的

Linux適用於服務器、開發環境和嵌入式系統。 1.作為服務器操作系統,Linux穩定高效,常用於部署高並發應用。 2.作為開發環境,Linux提供高效的命令行工具和包管理系統,提升開發效率。 3.在嵌入式系統中,Linux輕量且可定制,適合資源有限的環境。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver Mac版
視覺化網頁開發工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。