linux筆記:
https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482
前言:
在操作系統中,進程是資源分配和任務調度的基本單位。為了更好地管理系統資源,操作系統將進程的生命周期劃分為不同的狀態,幫助系統實現高效的資源調度與管理。linux操作系統在經典的進程狀態模型基礎上進行了擴展和細化,提供了更細粒度的控制。本文將詳細介紹操作系統進程狀態的基本概念,深入解析linux操作系統中的進程狀態,并通過代碼示例展示各個狀態的實現方式。
一、操作系統中的進程狀態概述
操作系統中的進程狀態是進程在生命周期中可能處于的不同狀態。這些狀態幫助操作系統識別進程的運行情況,并在不同狀態間進行合理的資源分配。操作系統中的經典進程狀態包括就緒、運行、阻塞和終止。
1.1 經典的進程狀態模型
典型的操作系統中,進程狀態可以分為以下幾種:
狀態
描述
就緒(Ready)
進程已準備好,等待CPU調度器分配CPU。
運行(Running)
進程正在占用CPU,正在執行中。
阻塞(Blocked/Waiting)
進程因需要等待資源或事件而無法繼續執行,暫停等待。
終止(Terminated)
進程執行完成或被強制終止,進入終止狀態,等待操作系統回收資源。
在這種經典模型中,進程會在不同狀態之間流轉。具體來說:
就緒 -> 運行:CPU調度器分配CPU給就緒狀態的進程。運行 -> 阻塞:進程等待I/O或其他資源時進入阻塞狀態。阻塞 -> 就緒:等待的條件滿足后,進程重新進入就緒隊列,等待CPU調度。運行 -> 終止:進程執行完畢或異常終止,進入終止狀態。1.2 進程狀態轉換圖

該圖展示了一個經典進程狀態的轉換流程。箭頭表示進程狀態轉換的可能路徑。
二、Linux操作系統中的進程狀態
Linux操作系統在經典的進程狀態基礎上進行了一系列擴展,允許內核更細粒度地控制進程,尤其是當系統資源緊張或多任務并發性很高時。Linux內核中的進程狀態可以使用ps命令或讀取/proc文件系統來查看進程的狀態信息。
2.1 Linux進程狀態的分類
Linux狀態
描述
TASK_RUNNING
正在運行或可以運行的進程,即就緒狀態。
TASK_INTERRUPTIBLE
可中斷等待狀態,等待期間可以被信號中斷并喚醒。
TASK_UNINTERRUPTIBLE
不可中斷等待狀態,等待期間不會被信號喚醒,通常用于等待設備I/O操作的完成。
TASK_STOPPED
進程被暫停,通常因收到SigsTOP等信號。
TASK_TRACED
進程被調試器(如gdb)控制。
EXIT_DEAD
進程已結束,即將被回收。
EXIT_ZOMBIE
僵尸狀態,進程結束但資源尚未被父進程回收。
TASK_DEAD
進程已徹底終止,資源已回收。
在進程的task_struct結構體中,state字段用來表示進程的當前狀態。根據內核中的定義,不同狀態的進程會被掛載在不同的等待隊列上,以實現細粒度的調度與控制。
2.2 各狀態的詳細解釋 TASK_RUNNING:進程正在運行或準備運行。它可以被調度器分配到CPU執行。TASK_RUNNING的進程始終是就緒隊列的一部分。 TASK_INTERRUPTIBLE:進程處于可中斷等待狀態,等待某一條件滿足。進程在此狀態下可以被信號喚醒。(關于信號的知識我們在后面會講) TASK_UNINTERRUPTIBLE:進程處于不可中斷的等待狀態。這通常用于等待特定資源(例如設備I/O操作完成)。進程在此狀態下不會被信號打斷,即便外部發送信號也不會響應。 TASK_STOPPED:進程被暫停,通常是由于接收到SIGSTOP信號或調試器干預,等待繼續或恢復信號。 TASK_TRACED:進程被調試工具(如gdb)跟蹤和控制。此狀態下的進程會暫停,直到調試器進一步控制。 EXIT_DEAD:進程終止后進入清理階段,等待系統回收資源。 EXIT_ZOMBIE:進程已結束,系統未回收其資源。僵尸進程會保留在系統中,直到其父進程調用wait()系統調用收集它的退出狀態。 TASK_DEAD:表示進程已徹底結束,系統已回收其所有資源。 2.3 Linux進程狀態表
Linux 狀態
符號
進程描述
TASK_RUNNING
R
進程正在運行或可以被調度器調度運行。
TASK_INTERRUPTIBLE
S
進程處于可中斷的睡眠狀態,等待條件滿足。
TASK_UNINTERRUPTIBLE
D
進程處于不可中斷的睡眠狀態,通常等待I/O。
TASK_STOPPED
T
進程暫停或已終止。
EXIT_ZOMBIE
Z
僵尸進程,等待父進程收回。
2.4 使用ps查看進程狀態
在Linux系統中,可以通過ps命令查看進程的狀態:
代碼語言:JavaScript代碼運行次數:0運行復制
ps -aux
ps命令會顯示每個進程的詳細信息,其中狀態列標記著每個進程的狀態。狀態的含義如下:
R:運行或就緒狀態。S:可中斷等待。D:不可中斷等待。T:停止。Z:僵尸狀態。
我們也可以通過ps命令查看某個指定的進程的信息:
代碼語言:javascript代碼運行次數:0運行復制
ps axj | grep 進程名字
三、代碼示例:實現Linux進程狀態的模擬
為了更好地理解Linux中的進程狀態,以下示例演示了不同狀態的應用。代碼展示了一個簡單的內核模塊,用于模擬進程進入阻塞狀態、喚醒狀態等。
3.1 阻塞等待狀態示例代碼語言:javascript代碼運行次數:0運行復制
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/wait.h>#include <linux/kthread.h>#include <linux/delay.h>static wait_queue_head_t wait_queue; // 定義等待隊列static int condition = 0;static struct task_struct *thread_waiter;static int waiter_thread(void *data) { printk(KERN_INFO "等待線程啟動...n"); wait_event_interruptible(wait_queue, condition != 0); // 可中斷等待 printk(KERN_INFO "等待線程被喚醒,繼續執行...n"); return 0;}static int __init wait_queue_init(void) { init_waitqueue_head(&wait_queue); // 初始化等待隊列 thread_waiter = kthread_run(waiter_thread, NULL, "waiter_thread"); if (IS_ERR(thread_waiter)) { printk(KERN_ERR "線程創建失敗n"); return PTR_ERR(thread_waiter); } msleep(5000); // 模擬一些操作 condition = 1; // 修改條件 wake_up_interruptible(&wait_queue); // 喚醒等待線程 return 0;}static void __exit wait_queue_exit(void) { printk(KERN_INFO "卸載模塊n");}module_init(wait_queue_init);module_exit(wait_queue_exit);MODULE_LICENSE("GPL");
在上面的代碼中:
waiter_thread進入可中斷等待狀態,等待條件滿足。當條件變量condition改變時,wake_up_interruptible喚醒等待隊列中的線程,使waiter_thread進入可運行狀態。3.2 僵尸進程示例
僵尸進程是進程狀態的特殊情況,無法直接控制其生成。為了生成僵尸進程,可以在一個子進程中完成工作后立刻終止,但不等待父進程收回資源。示例如下:
代碼語言:javascript代碼運行次數:0運行復制
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main() { pid_t pid = fork(); if (pid == 0) { // 子進程,立即退出成為僵尸進程 printf("子進程:PID=%dn", getpid()); exit(0); } else { // 父進程,等待5秒以查看僵尸進程 printf("父進程:PID=%dn", getpid()); sleep(5); printf("父進程結束,僵尸子進程將被回收。n"); } return 0;}
在這個代碼中,子進程在終止后不被父進程立即回收,因此變成僵尸狀態。可以使用ps命令查看該僵尸進程,發現它的狀態為Z。
3.3 孤兒進程示例
除了