linux wait 子孙进程,Linux-进程基础
知識點比較雜,需要注意邏輯聯系
1、程序與進程的區別
程序是靜態的,存放在磁盤上,是指令的集合。
進程是程序運行的實例,一個程序運行產生一次產生一個進程。
關于進程,每個進程都有自己的pid,都有自己的PCB,PCB(進程控制塊)記錄了進程使用到的資源。
進程是資源分配的基本的單位,但是不是執行的基本單位。
在Linux操作系統下,進程之間的關系是父子關系或者兄弟關系,所有的用戶級的進程形成了一棵樹。可以使用pstree查看。
pstree命令以樹狀圖顯示進程間的關系(display a tree of processes)。ps命令可以顯示當前正在運行的那些進程的信息,但是對于它們之間的關系卻顯示得不夠清晰。在Linux系統中,系統調用fork可以創建子進程,通過子shell也可以創建子進程,Linux系統中進程之間的關系天生就是一棵樹,樹的根就是進程PID為1的init進程。
常用參數
格式:pstree
以樹狀圖顯示進程,只顯示進程的名字,且相同進程合并顯示。
格式:pstree -p
以樹狀圖顯示進程,還顯示進程PID。
格式:pstree
格式:pstree -p
以樹狀圖顯示進程PID為的進程以及子孫進程,如果有-p參數則同時顯示每個進程的PID。
格式:pstree -a
以樹狀圖顯示進程,相同名稱的進程不合并顯示,并且會顯示命令行參數,如果有-p參數則同時顯示每個進程的PID。
因為pstree輸出的信息可能比較多,所以最好與more/less配合使用。
init是這棵樹的樹根,也是1好進程。是用戶進程的第一個進程。環用戶自定義變量不能被子進程繼承,環境變量可以被子進程繼承。
2、創建新進程
使用fork(2)創建新進程
#include
pid_t fork(void);
功能:
參數:
返回值:
失敗:在父進程-1被返回,子進程不被創建,errno被設置
成功:在父進程里返回子進程的PID,子進程得到0的返回值
注意:這里不是一個函數返回兩個值,而是已經存在了兩個進程,是兩個fork的返回值
可以使用ps -aux命令查看進程信息
使用pstree查看進程樹,Linux下的三個特殊進程:idle進程(PID=0),init進程(PID=1),和kthreadd(PID=2)
idle進程由系統自動創建,運行在內核態
idle進程其pid=0,其前身是系統創建的第一個進程,也是唯一一個沒有通過fork或者kernel_thread產生的進程。完成加載系統后,演變為進程調度、交換。
kthreadd進程由idle通過kernel_thread創建,并始終運行在內核空間,負責所有內核進程的調度和管理。
它的任務就是管理和調度其他內核線程kernel_thread, 會循環執行一個kthread的函數,該函數的作用就是運行kthread_create_list全局鏈表中維護的kthread, 當我們調用kernel_thread創建的內核線程會被加入到此鏈表中,因此所有的內核線程都是直接或者間接的以kthreadd為父進程 。
init進程由idle通過kernel_thread創建,在內核空間完成初始化后,加載init程序
在這里我們就主要講解下init進程,init進程由0進程創建,完成系統的初始化,是系統中所有其他用戶進程的祖先進程
Linux中的所有進程都是由init進程創建并運行的。首先Linux內核啟動,然后在用戶空間中啟動init進程,再啟動其他系統進程。在系統啟動完成后,init將變成為守護進程監視系統其他進程。
所以說init進程是Linux系統操作中不可缺少的程序之一,如果內核找不到init進程就會試著運行/bin/sh,如果運行失敗,系統的啟動也會失敗。
3、終止進程
exit(3)和return的區別,return是函數的返回(可以使用echo $?查看最近一次返回結果),exit是進程的結束
exit(3)
#include
void exit(int status)
功能:
終止一個正常進程,status&0377的值返回給父進程
參數:
status:狀態碼
返回值:
不返回
進程退出之前,需要調用一些處理函數進行資源清理,這些函數需要進行注冊
atexit(3)
atexit函數是一個特殊的函數,它是在正常程序退出時調用的函數,我們把他叫為登記函數
#include
int atexit(void (*func)(void))
功能
C 庫函數?int atexit(void (*func)(void))?當程序正常終止時,調用指定的函數?func。您可以在任何地方注冊你的終止函數,但它會在程序終止的時候被調用。
參數
func?- 在程序終止時被調用的函數。
返回值
如果函數成功注冊,則該函數返回零,否則返回一個非零值。
實例
下面的實例演示了 atexit() 函數的用法。
#include
#include
void functionA ()
{
printf("這是函數A\n");
}
int main ()
{
/* 注冊終止函數 */
atexit(functionA );
printf("啟動主程序...\n");
printf("退出主程序...\n");
return(0);
}
在一個程序中最多可以用atexit()注冊32個處理函數,這些處理函數的調用順序與其注冊的順序相反,也即最先注冊的最后調用,最后注冊的最先調用。
執行結果:
執行
before exit()!
on_exit(3)
相關函數 _exit,atexit,exit
函數原型
#include
int on_exit(void (* function)(int,void*),void *arg);
返回值 如果執行成功則返回0,否則返回-1,失敗原因存于errno中。
函數說明 on_exit()用來設置一個程序正常結束前調用的函數。當程序通過調用exit()
或從main中返回時,參數function所指定的函數會先被調用,然后才真正由exit()結束
程序。參數arg指針會傳給參數function函數,詳細情況請見范例。
#include
void my_exit(int status,void *arg)
{
printf(“before exit()!\n”);
printf(“exit (%d)\n”,status);
printf(“arg = %s\n”,(char*)arg);
}
main()
{
char * str=”test”;
on_exit(my_exit,(void *)str);
exit(1234);
}
執行結果:
執行 before exit()!
exit (1234)
arg = test
4、子進程回收
進程結束后,父進程會回收子進程資源,wait(2)、waitpid(2)系統調用可以回收子進程資源。
如果父進程先于子進程結束,那么子進程的父進程將變為init進程。
wait(2)
#include
#include
功能:
這些系統調用用于獲取子進程狀態變化和狀態信息。狀態的變化可以認為是:(1)子進程終止;(2)子進程被信號中止;子進程被信號喚醒。
參數:
參數status如果不是一個空指針,則終止進程的終止狀態就存放在statloc所指向的單元。
參數status如果是一個空指針,則表示父進程不關心子進程的終止狀態
子進程的的退出狀態存放在這塊地址中,可以使用宏檢測退出原因。
WIFEXITED(status):如果子進程正常結束則為非0 值.
WEXITSTATUS(status):取得子進程exit()返回的結束代碼, 一般會先用WIFEXITED 來判斷是否正常結束才能使用此宏.
WIFSIGNALED(status):如果子進程是因為信號而結束則此宏值為真
WTERMSIG(status):取得子進程因信號而中止的信號代碼, 一般會先用WIFSIGNALED 來判斷后才使用此宏.
WIFSTOPPED(status):如果子進程處于暫停執行情況則此宏值為真. 一般只有使用WUNTRACED時才會有此情況.
WSTOPSIG(status):取得引發子進程暫停的信號代碼, 一般會先用WIFSTOPPED 來判斷后才使用此宏.
kill命令用于刪除執行中的程序或工作。
kill可將指定的信息送至程序。預設的信息為SIGTERM(15),可將指定程序終止。若仍無法終止該程序,可使用SIGKILL(9)信息嘗試強制刪除程序。程序或工作的編號可利用ps指令或jobs指令查看。
返回值:
是一個阻塞函數,如果沒有可以回收的子進程,則為阻塞狀態
如果無子進程,則返回-1
如果回收成功,則返回子進程的pid
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 /***********************************************************
9
10
11
12 ***********************************************************/
13 void waitprocess();
14
15
16 int main(int argc, char * argv[])
17 {
18 waitprocess();
19
20 }
21
22 void waitprocess()
23 {
24
25 int count = 0;
26
27 pid_t pid = fork();
28 int status = -1;
29
30 if(pid<0)
31 {
32 printf("fork error for %m\n",errno );
33 }else if(pid>0)
34 {
35 printf("this is parent ,pid = %d\n",getpid() );
36 wait(&status);//父進程執行到此,馬上阻塞自己,直到有子進程結束。當發現有子進程結束時,就會回收它的資源。
37
38 }else
39 {
40 printf("this is child , pid = %d , ppid = %d\n",getpid(),getppid() );
41 int i;
42
43 for (i = 0; i < 10; i++) {
44 count++;
45 sleep(1);
46
47 printf("count = %d\n", count) ;
48
49 }
50
51 exit(5);
52
53 }
54 printf("child exit status is %d\n", WEXITSTATUS(status));//status是按位存儲的狀態信息,需要調用相應的宏來還原一下
55
56 printf("end of program from pid = %d\n",getpid() );
57
58
59 }
執行結果
通常利用如下代碼來判斷進程的終止原因,和終止信號來源。
wait(&status);
...
//檢測進程是否被信號終止
if(WIFSIGNALED(status)){
//輸出終止子進程的信號編號
printf("signum:%d\n",WTERMSIG(s));
}
在命令行使用kill命令終止相關進程,上述代碼即可輸出終止進程的相關信息。
子進程終止,但是父進程并未回收子進程的相關資源,這時候子進程處于僵尸狀態,成為僵尸進程
waitpid(2)
pid_t waitpid(pid_t pid, int *status, int options);
功能:
等待進程狀態改變。waitpid可以等待任意子進程或者一組子進程的終止;可以設置成阻塞狀態,也可以設置成非阻塞狀態。
參數:
pid:
pid>0只等待進程ID等于pid的子進程,不管其它已經有多少子進程運行結束退出了,只要指定的子進程還沒有結束,waitpid就會一直等下去。
pid=-1等待任何一個子進程退出,沒有任何限制,此時waitpid和wait的作用一模一樣。
pid=0時等待同一個進程組中的任何子進程,如果子進程已經加入了別的進程組,waitpid不會對它做任何理睬。
pid
status:
參數status如果不是一個空指針,則終止進程的終止狀態就存放在status所指向的單元。
參數status如果是一個空指針,則表示父進程不關心子進程的終止狀態
option:
WNOHANG若由pid指定的子進程未發生狀態改變(沒有結束),則waitpid()不阻塞,立即返回0
WUNTRACED返回終止子進程信息和因信號停止的子進程信息
WCONTINUED返回收到SIGCONT信號而恢復執行的已停止子進程狀態信息
0:阻塞
返回值:
成功成功結束運行的子進程的進程號
失敗返回-1
WNOHANG被設置時 沒有子進程退出返回0
wait(&status)等價于waitpid(-1,&status,0)
疑問:如果被設置為非阻塞,父進程先于子進程結束,子進程變為孤進程?由init調用wait回收?
筆記參考: https://www.cnblogs.com/king-77024128/articles/2684317.html
https://www.cnblogs.com/leijiangtao/p/4483009.html
標簽:status,基礎,void,pid,exit,Linux,進程,include
來源: https://www.cnblogs.com/ptfe/p/10972475.html
總結
以上是生活随笔為你收集整理的linux wait 子孙进程,Linux-进程基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Qt creator5.7 OpenCV
- 下一篇: 点击部分刷新html ajax,一文全解