一.進程的七種狀態
1.七種狀態如下:
①R(運行狀態)(這個狀態並不是說明當前進程在CPU里運行,而是說當前進程處理運行隊列里)
②S(淺度睡眠狀態)
③D(深度睡眠狀態)(不能被終止)
④T(停止狀態)
⑤t (追蹤狀態)
⑥X(死亡狀態)
⑦Z(僵屍狀態)
注意:狀態后面帶+表示前台進程,不帶+表示后台進程(前台進程:當前只能有一個進程做事;后台進程:當前可以有很多進程做事)
2.如何修改進程的狀態?
①首先創建一個進程,並讓其變成一個后台進程(后面加上一個&)。
②我們可以看到test進程的pid為1785,狀態為R(下面還有一個進程是執行查詢進程信息時創建的進程grep)。
③將test進程的狀態由R變為T(停止)狀態。
首先通過kill -l查詢這些信號處理列表。
可以發現19號信號(SIGSTOP)是停止進程的信號。
執行19號信號:(kill -19 1785)注意必須在19前面加上-(也可以將19換為信號名,如可以寫kill -SIGSTOP 1785)
④如果想讓剛剛停止的進程繼續執行,則可以用kill -18 1785
二.僵屍進程
1.什么叫僵屍進程?
當一個子進程退出后,其父進程還在繼續執行,子進程的退出信息並沒有被父進程接收到,但是一個進程的退出信息必須被父進程或一些有聯系的進程接收到,所以當前進程會一直處於僵死狀態。
2.為什么子進程的退出信息要被接收到呢?
因為一個進程的退出方式有三種(程序執行完結果正確即正常退出,程序執行完結果不正確,程序還沒有執行完),父進程必須要知道子進程到底是以何種狀態退出的,如果子進程不是正常退出,則父進程還要創建子進程執行這件事。
3.處於僵屍狀態的進程會一直等待其父進程讀取其退出信息。
4.所以,只要子進程退出,而父進程還在執行,但父進程沒有讀取子進程的狀態信息,則子進程會變成一個僵屍進程。
5.創建一個僵屍進程(只要讓子進程先退出,父進程一直執行)
例如可以編寫一個程序,前5秒該程序會讓父子進程同時運行,5秒之后只有父進程在一直運行,所以我們可以知道5秒后子進程的狀態會變為Z狀態。
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { //先創建一個子進程 pid_t pid = fork(); if (pid == 0) { //child //讓子進程先退出,父進程一直執行 printf("child pid=%d ppid=%d\n", getpid(), getppid()); sleep(5); exit(1); //讓子進程睡5秒后推出 } else if (pid > 0) { //parent //讓父進程一直執行 while (1) { printf("parent pid=%d ppid=%d\n", getpid(), getppid()); sleep(2); //讓父進程每隔兩秒打印這個 } } }
6.在另一個終端下啟動監控,查看進程的狀態:
啟動監控的命令如下:while :;do ps aux | grep 'jiangshi' | grep -v grep;sleep 1;echo "#####################################";done
則命令執行后的結果如下:(可以發現5秒后子進程由S狀態變為Z狀態)
三.因為僵屍進程的是由於父進程沒有接收到子進程的返回信息,那么僵屍進程肯定是有危害的,那么僵屍進程有什么危害呢?
1.一個進程當他處於僵屍狀態時,它這個狀態會一直維持下去,因為它必須要告訴父進程它的返回信息。
2.又由於操作系統必須要用數據來維持一個進程的狀態,所以僵屍狀態也是進程的基本信息,也需要PCB來維護,所以一個處於僵屍狀態的進程一直需要維護。維護就會有空間的消耗,這些消耗的空間又沒有被釋放,所以就會導致內存資源的浪費,就會導致內存泄露的問題。
(補充一點,不只是C語言或C++里指針沒有釋放會導致內存泄露,這里的僵屍狀態沒有被處理也會導致內存泄露)。
注意:當一個進程變為僵屍進程后,無法用kill -9來殺死這個進程。
四.如何避免僵屍進程?
1.僵屍進程是由於子進程退出但是父進程沒有接收其退出信息而導致了。
2.只要讓子進程退出后,父進程接收子進程的退出信息就可以避免僵屍進程。
3.所以父進程通過進程等待的方式,回收子進程的資源,獲取子進程的信息。
五.孤兒進程
1.什么是孤兒進程?
當一個子進程還在執行時,它的父進程已經退出了,那么這個子進程的退出信息也沒有被父進程接收到,如果子進程的退出信息沒有被別的進程接收到,那么這個子進程就會變成一個僵屍進程,所以孤兒進程可能會引發僵屍進程。所以這個子進程必須被其他進程所領養,領養它的進程為1號進程,則它的退出信息會被1號進程所接收。
2.如果父進程退出,父進程會變成僵屍進程嗎?
不會,因為父進程的父進程為bash,父進程的退出信息會由bash接收到,這些我們看不到。
3.創建一個孤兒進程(只需要讓父進程先退出,子進程繼續執行)
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { //孤兒進程:父進程先退出,子進程繼續執行 pid_t pid = fork(); if (pid == 0) { //子進程 while (1) { printf("child pid=%d ppid=%d\n", getpid(), getppid()); sleep(3); } } else if (pid > 0) { //parent printf("parent pid=%d ppid=%d\n", getpid(), getppid()); sleep(5); exit(1); } else { perror("fork()"); } return 0; }
4.打開一個監控,由於這里還需要看到父進程的id,所以這里的啟動監控的命令改為while :;do ps axj | grep 'guer' | grep -v grep;sleep 1;echo "###################################################################";done
執行結果:(我們可以發現5秒之后子進程的父進程變為1號進程,說明當5秒之后父進程退出后,子進程被1號進程領養)