Linux——進程狀態

為了理解正在運行的進程的含義,我們需要了解進程的不同狀態。進程在linux內核中也被稱為任務。進程的狀態由task_struct中的一個整型變量表示。以下是kernel源代碼中定義的進程狀態:

/*   * The task state array is a strange "bitmap" of   * reasons to sleep. Thus "running" is zero, and   * you can test for combinations of others with   * simple bit tests.   */  static const char * const task_state_array[] = {    "R (running)", /* 0 */    "S (sleeping)", /* 1 */    "D (disk sleep)", /* 2 */    "T (stopped)", /* 4 */    "t (tracing stop)", /* 8 */    "X (dead)", /* 16 */    "Z (zombie)", /* 32 */  };

為什么需要進程狀態?在日常生活中,如果你感冒了,你可能會告訴室友今天狀態不好不去上課了。這里的狀態決定了你后續的行動——不去上課。在linux中,操作系統需要根據進程的狀態來決定對這些進程的后續操作。

1.1 通俗的五種進程狀態

進程的狀態可以通俗地分為五種:創建狀態、就緒狀態、阻塞狀態、執行狀態和終止狀態。最基本的狀態包括:運行狀態、就緒狀態和阻塞狀態。

  • 就緒狀態:進程已經具備運行條件,但由于沒有空閑的CPU而暫時不能運行。

  • 運行狀態:進程正在運行,占用CPU資源。

  • 阻塞狀態:進程因為等待某一事件而暫時不能運行,如執行sleep或等待輸入。

  • 創建狀態:進程正在被創建,操作系統為其分配資源、初始化PCB。

  • 終止狀態:進程從系統中被撤銷,操作系統回收進程擁有的資源。

1.2 進程的具體狀態

前面提到的狀態與我們之前描述的具體狀態有所不同,具體狀態是通俗狀態的具體實例。讓我們再看看代碼:

/*   * The task state array is a strange "bitmap" of   * reasons to sleep. Thus "running" is zero, and   * you can test for combinations of others with   * simple bit tests.   */  static const char * const task_state_array[] = {    "R (running)", /* 0 */    "S (sleeping)", /* 1 */    "D (disk sleep)", /* 2 */    "T (stopped)", /* 4 */    "t (tracing stop)", /* 8 */    "X (dead)", /* 16 */    "Z (zombie)", /* 32 */  };
  • R 運行狀態(running):并不意味著進程一定在運行,它表示進程要么在運行中,要么在運行隊列中,相當于就緒狀態和運行狀態。
  • S 睡眠狀態(sleeping):進程在等待事件完成(也稱為可中斷睡眠),相當于阻塞狀態。
  • D 磁盤休眠狀態(disk sleep):有時也稱為不可中斷睡眠狀態,進程通常等待I/O操作結束。
  • T 停止狀態(stopped):可以通過發送SigsTOP信號給進程來停止進程,暫停的進程可以通過SIGCONT信號繼續運行。
  • X 死亡狀態(dead):這是一個返回狀態,不會在任務列表中顯示。
  • Z 僵尸狀態(zombie):當進程退出且父進程未讀取其返回代碼時,進程進入僵尸狀態。

1.3 查看進程狀態

我們可以通過以下命令查看進程狀態:

ps aux / ps axj 命令
  • ps aux:顯示所有進程,以用戶為主。
  • ps axj:顯示所有進程,并顯示進程ID、父進程ID等信息。

讓我們編寫一個程序并觀察其狀態:

#include <stdio.h> #include <unistd.h> int main(){     while(1){         printf("I am a process!n");         sleep(1); //休眠一秒     }     return 0; }

Makefile配置如下:

mybin:test1.c     gcc -o mybin test1.c .PHONY:clean clean:     rm -f mybin

使用兩個xshell窗口,一個運行程序,另一個觀察進程狀態。我們還可以編寫一個循環命令來查看進程狀態:

while :;do ps ajx|head -1 && ps ajx|grep mybin|grep -v grep;sleep 1; done

每秒打印一次mybin進程的狀態。運行程序后,我們可以看到進程的STAT狀態為S,這是因為程序中的sleep函數會讓進程休眠一秒。如果去掉sleep,STAT仍然會是S,因為printf也會導致短暫的休眠。要顯示R狀態,可以去掉printf,讓程序執行死循環。

1.4 介紹僵尸進程與孤兒進程

  • Z(zombie) – 僵尸進程:當進程退出且父進程未讀取其返回代碼時,進程進入僵尸狀態。僵尸進程會一直保持在進程表中,等待父進程讀取其退出狀態。僵尸進程會導致內存泄漏。

    我們可以創建一個維持30秒的僵尸進程:

    #include <stdio.h> #include <stdlib.h> int main(){     pid_t id = fork();     if(id > 0){         printf("parent[%d] is sleeping...n",getpid());         sleep(30);     }else{         printf("child[%d] is begin Z...n",getpid());         sleep(5);         exit(-1);     }     return 0; }
  • 孤兒進程:如果父進程提前退出,子進程后退出并進入Z狀態,子進程會成為孤兒進程,由1號進程收養。

    我們可以編寫一個程序來觀察孤兒進程:

    #include <stdio.h> #include <stdlib.h> int main(){     pid_t id = fork();     if(id > 0){         printf("parent[%d] is sleeping...n",getpid());         sleep(3);         exit(-1);     }else{         printf("child[%d] is begin Z...n",getpid());         sleep(10);     }     return 0; }

通過這些示例,我們可以看到子進程被1號進程接管。

Linux——進程狀態

Linux——進程狀態

Linux——進程狀態

Linux——進程狀態

Linux——進程狀態

Linux——進程狀態

? 版權聲明
THE END
喜歡就支持一下吧
點贊10 分享