linux wait 子孙进程,Linux-进程基础
知識(shí)點(diǎn)比較雜,需要注意邏輯聯(lián)系
1、程序與進(jìn)程的區(qū)別
程序是靜態(tài)的,存放在磁盤(pán)上,是指令的集合。
進(jìn)程是程序運(yùn)行的實(shí)例,一個(gè)程序運(yùn)行產(chǎn)生一次產(chǎn)生一個(gè)進(jìn)程。
關(guān)于進(jìn)程,每個(gè)進(jìn)程都有自己的pid,都有自己的PCB,PCB(進(jìn)程控制塊)記錄了進(jìn)程使用到的資源。
進(jìn)程是資源分配的基本的單位,但是不是執(zhí)行的基本單位。
在Linux操作系統(tǒng)下,進(jìn)程之間的關(guān)系是父子關(guān)系或者兄弟關(guān)系,所有的用戶級(jí)的進(jìn)程形成了一棵樹(shù)。可以使用pstree查看。
pstree命令以樹(shù)狀圖顯示進(jìn)程間的關(guān)系(display a tree of processes)。ps命令可以顯示當(dāng)前正在運(yùn)行的那些進(jìn)程的信息,但是對(duì)于它們之間的關(guān)系卻顯示得不夠清晰。在Linux系統(tǒng)中,系統(tǒng)調(diào)用fork可以創(chuàng)建子進(jìn)程,通過(guò)子shell也可以創(chuàng)建子進(jìn)程,Linux系統(tǒng)中進(jìn)程之間的關(guān)系天生就是一棵樹(shù),樹(shù)的根就是進(jìn)程PID為1的init進(jìn)程。
常用參數(shù)
格式:pstree
以樹(shù)狀圖顯示進(jìn)程,只顯示進(jìn)程的名字,且相同進(jìn)程合并顯示。
格式:pstree -p
以樹(shù)狀圖顯示進(jìn)程,還顯示進(jìn)程PID。
格式:pstree
格式:pstree -p
以樹(shù)狀圖顯示進(jìn)程PID為的進(jìn)程以及子孫進(jìn)程,如果有-p參數(shù)則同時(shí)顯示每個(gè)進(jìn)程的PID。
格式:pstree -a
以樹(shù)狀圖顯示進(jìn)程,相同名稱的進(jìn)程不合并顯示,并且會(huì)顯示命令行參數(shù),如果有-p參數(shù)則同時(shí)顯示每個(gè)進(jìn)程的PID。
因?yàn)閜stree輸出的信息可能比較多,所以最好與more/less配合使用。
init是這棵樹(shù)的樹(shù)根,也是1好進(jìn)程。是用戶進(jìn)程的第一個(gè)進(jìn)程。環(huán)用戶自定義變量不能被子進(jìn)程繼承,環(huán)境變量可以被子進(jìn)程繼承。
2、創(chuàng)建新進(jìn)程
使用fork(2)創(chuàng)建新進(jìn)程
#include
pid_t fork(void);
功能:
參數(shù):
返回值:
失敗:在父進(jìn)程-1被返回,子進(jìn)程不被創(chuàng)建,errno被設(shè)置
成功:在父進(jìn)程里返回子進(jìn)程的PID,子進(jìn)程得到0的返回值
注意:這里不是一個(gè)函數(shù)返回兩個(gè)值,而是已經(jīng)存在了兩個(gè)進(jìn)程,是兩個(gè)fork的返回值
可以使用ps -aux命令查看進(jìn)程信息
使用pstree查看進(jìn)程樹(shù),Linux下的三個(gè)特殊進(jìn)程:idle進(jìn)程(PID=0),init進(jìn)程(PID=1),和kthreadd(PID=2)
idle進(jìn)程由系統(tǒng)自動(dòng)創(chuàng)建,運(yùn)行在內(nèi)核態(tài)
idle進(jìn)程其pid=0,其前身是系統(tǒng)創(chuàng)建的第一個(gè)進(jìn)程,也是唯一一個(gè)沒(méi)有通過(guò)fork或者kernel_thread產(chǎn)生的進(jìn)程。完成加載系統(tǒng)后,演變?yōu)檫M(jìn)程調(diào)度、交換。
kthreadd進(jìn)程由idle通過(guò)kernel_thread創(chuàng)建,并始終運(yùn)行在內(nèi)核空間,負(fù)責(zé)所有內(nèi)核進(jìn)程的調(diào)度和管理。
它的任務(wù)就是管理和調(diào)度其他內(nèi)核線程kernel_thread, 會(huì)循環(huán)執(zhí)行一個(gè)kthread的函數(shù),該函數(shù)的作用就是運(yùn)行kthread_create_list全局鏈表中維護(hù)的kthread, 當(dāng)我們調(diào)用kernel_thread創(chuàng)建的內(nèi)核線程會(huì)被加入到此鏈表中,因此所有的內(nèi)核線程都是直接或者間接的以kthreadd為父進(jìn)程 。
init進(jìn)程由idle通過(guò)kernel_thread創(chuàng)建,在內(nèi)核空間完成初始化后,加載init程序
在這里我們就主要講解下init進(jìn)程,init進(jìn)程由0進(jìn)程創(chuàng)建,完成系統(tǒng)的初始化,是系統(tǒng)中所有其他用戶進(jìn)程的祖先進(jìn)程
Linux中的所有進(jìn)程都是由init進(jìn)程創(chuàng)建并運(yùn)行的。首先Linux內(nèi)核啟動(dòng),然后在用戶空間中啟動(dòng)init進(jìn)程,再啟動(dòng)其他系統(tǒng)進(jìn)程。在系統(tǒng)啟動(dòng)完成后,init將變成為守護(hù)進(jìn)程監(jiān)視系統(tǒng)其他進(jìn)程。
所以說(shuō)init進(jìn)程是Linux系統(tǒng)操作中不可缺少的程序之一,如果內(nèi)核找不到init進(jìn)程就會(huì)試著運(yùn)行/bin/sh,如果運(yùn)行失敗,系統(tǒng)的啟動(dòng)也會(huì)失敗。
3、終止進(jìn)程
exit(3)和return的區(qū)別,return是函數(shù)的返回(可以使用echo $?查看最近一次返回結(jié)果),exit是進(jìn)程的結(jié)束
exit(3)
#include
void exit(int status)
功能:
終止一個(gè)正常進(jìn)程,status&0377的值返回給父進(jìn)程
參數(shù):
status:狀態(tài)碼
返回值:
不返回
進(jìn)程退出之前,需要調(diào)用一些處理函數(shù)進(jìn)行資源清理,這些函數(shù)需要進(jìn)行注冊(cè)
atexit(3)
atexit函數(shù)是一個(gè)特殊的函數(shù),它是在正常程序退出時(shí)調(diào)用的函數(shù),我們把他叫為登記函數(shù)
#include
int atexit(void (*func)(void))
功能
C 庫(kù)函數(shù)?int atexit(void (*func)(void))?當(dāng)程序正常終止時(shí),調(diào)用指定的函數(shù)?func。您可以在任何地方注冊(cè)你的終止函數(shù),但它會(huì)在程序終止的時(shí)候被調(diào)用。
參數(shù)
func?- 在程序終止時(shí)被調(diào)用的函數(shù)。
返回值
如果函數(shù)成功注冊(cè),則該函數(shù)返回零,否則返回一個(gè)非零值。
實(shí)例
下面的實(shí)例演示了 atexit() 函數(shù)的用法。
#include
#include
void functionA ()
{
printf("這是函數(shù)A\n");
}
int main ()
{
/* 注冊(cè)終止函數(shù) */
atexit(functionA );
printf("啟動(dòng)主程序...\n");
printf("退出主程序...\n");
return(0);
}
在一個(gè)程序中最多可以用atexit()注冊(cè)32個(gè)處理函數(shù),這些處理函數(shù)的調(diào)用順序與其注冊(cè)的順序相反,也即最先注冊(cè)的最后調(diào)用,最后注冊(cè)的最先調(diào)用。
執(zhí)行結(jié)果:
執(zhí)行
before exit()!
on_exit(3)
相關(guān)函數(shù) _exit,atexit,exit
函數(shù)原型
#include
int on_exit(void (* function)(int,void*),void *arg);
返回值 如果執(zhí)行成功則返回0,否則返回-1,失敗原因存于errno中。
函數(shù)說(shuō)明 on_exit()用來(lái)設(shè)置一個(gè)程序正常結(jié)束前調(diào)用的函數(shù)。當(dāng)程序通過(guò)調(diào)用exit()
或從main中返回時(shí),參數(shù)function所指定的函數(shù)會(huì)先被調(diào)用,然后才真正由exit()結(jié)束
程序。參數(shù)arg指針會(huì)傳給參數(shù)function函數(shù),詳細(xì)情況請(qǐng)見(jiàn)范例。
#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);
}
執(zhí)行結(jié)果:
執(zhí)行 before exit()!
exit (1234)
arg = test
4、子進(jìn)程回收
進(jìn)程結(jié)束后,父進(jìn)程會(huì)回收子進(jìn)程資源,wait(2)、waitpid(2)系統(tǒng)調(diào)用可以回收子進(jìn)程資源。
如果父進(jìn)程先于子進(jìn)程結(jié)束,那么子進(jìn)程的父進(jìn)程將變?yōu)閕nit進(jìn)程。
wait(2)
#include
#include
功能:
這些系統(tǒng)調(diào)用用于獲取子進(jìn)程狀態(tài)變化和狀態(tài)信息。狀態(tài)的變化可以認(rèn)為是:(1)子進(jìn)程終止;(2)子進(jìn)程被信號(hào)中止;子進(jìn)程被信號(hào)喚醒。
參數(shù):
參數(shù)status如果不是一個(gè)空指針,則終止進(jìn)程的終止?fàn)顟B(tài)就存放在statloc所指向的單元。
參數(shù)status如果是一個(gè)空指針,則表示父進(jìn)程不關(guān)心子進(jìn)程的終止?fàn)顟B(tài)
子進(jìn)程的的退出狀態(tài)存放在這塊地址中,可以使用宏檢測(cè)退出原因。
WIFEXITED(status):如果子進(jìn)程正常結(jié)束則為非0 值.
WEXITSTATUS(status):取得子進(jìn)程exit()返回的結(jié)束代碼, 一般會(huì)先用WIFEXITED 來(lái)判斷是否正常結(jié)束才能使用此宏.
WIFSIGNALED(status):如果子進(jìn)程是因?yàn)樾盘?hào)而結(jié)束則此宏值為真
WTERMSIG(status):取得子進(jìn)程因信號(hào)而中止的信號(hào)代碼, 一般會(huì)先用WIFSIGNALED 來(lái)判斷后才使用此宏.
WIFSTOPPED(status):如果子進(jìn)程處于暫停執(zhí)行情況則此宏值為真. 一般只有使用WUNTRACED時(shí)才會(huì)有此情況.
WSTOPSIG(status):取得引發(fā)子進(jìn)程暫停的信號(hào)代碼, 一般會(huì)先用WIFSTOPPED 來(lái)判斷后才使用此宏.
kill命令用于刪除執(zhí)行中的程序或工作。
kill可將指定的信息送至程序。預(yù)設(shè)的信息為SIGTERM(15),可將指定程序終止。若仍無(wú)法終止該程序,可使用SIGKILL(9)信息嘗試強(qiáng)制刪除程序。程序或工作的編號(hào)可利用ps指令或jobs指令查看。
返回值:
是一個(gè)阻塞函數(shù),如果沒(méi)有可以回收的子進(jìn)程,則為阻塞狀態(tài)
如果無(wú)子進(jìn)程,則返回-1
如果回收成功,則返回子進(jìn)程的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);//父進(jìn)程執(zhí)行到此,馬上阻塞自己,直到有子進(jìn)程結(jié)束。當(dāng)發(fā)現(xiàn)有子進(jìn)程結(jié)束時(shí),就會(huì)回收它的資源。
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是按位存儲(chǔ)的狀態(tài)信息,需要調(diào)用相應(yīng)的宏來(lái)還原一下
55
56 printf("end of program from pid = %d\n",getpid() );
57
58
59 }
執(zhí)行結(jié)果
通常利用如下代碼來(lái)判斷進(jìn)程的終止原因,和終止信號(hào)來(lái)源。
wait(&status);
...
//檢測(cè)進(jìn)程是否被信號(hào)終止
if(WIFSIGNALED(status)){
//輸出終止子進(jìn)程的信號(hào)編號(hào)
printf("signum:%d\n",WTERMSIG(s));
}
在命令行使用kill命令終止相關(guān)進(jìn)程,上述代碼即可輸出終止進(jìn)程的相關(guān)信息。
子進(jìn)程終止,但是父進(jìn)程并未回收子進(jìn)程的相關(guān)資源,這時(shí)候子進(jìn)程處于僵尸狀態(tài),成為僵尸進(jìn)程
waitpid(2)
pid_t waitpid(pid_t pid, int *status, int options);
功能:
等待進(jìn)程狀態(tài)改變。waitpid可以等待任意子進(jìn)程或者一組子進(jìn)程的終止;可以設(shè)置成阻塞狀態(tài),也可以設(shè)置成非阻塞狀態(tài)。
參數(shù):
pid:
pid>0只等待進(jìn)程ID等于pid的子進(jìn)程,不管其它已經(jīng)有多少子進(jìn)程運(yùn)行結(jié)束退出了,只要指定的子進(jìn)程還沒(méi)有結(jié)束,waitpid就會(huì)一直等下去。
pid=-1等待任何一個(gè)子進(jìn)程退出,沒(méi)有任何限制,此時(shí)waitpid和wait的作用一模一樣。
pid=0時(shí)等待同一個(gè)進(jìn)程組中的任何子進(jìn)程,如果子進(jìn)程已經(jīng)加入了別的進(jìn)程組,waitpid不會(huì)對(duì)它做任何理睬。
pid
status:
參數(shù)status如果不是一個(gè)空指針,則終止進(jìn)程的終止?fàn)顟B(tài)就存放在status所指向的單元。
參數(shù)status如果是一個(gè)空指針,則表示父進(jìn)程不關(guān)心子進(jìn)程的終止?fàn)顟B(tài)
option:
WNOHANG若由pid指定的子進(jìn)程未發(fā)生狀態(tài)改變(沒(méi)有結(jié)束),則waitpid()不阻塞,立即返回0
WUNTRACED返回終止子進(jìn)程信息和因信號(hào)停止的子進(jìn)程信息
WCONTINUED返回收到SIGCONT信號(hào)而恢復(fù)執(zhí)行的已停止子進(jìn)程狀態(tài)信息
0:阻塞
返回值:
成功成功結(jié)束運(yùn)行的子進(jìn)程的進(jìn)程號(hào)
失敗返回-1
WNOHANG被設(shè)置時(shí) 沒(méi)有子進(jìn)程退出返回0
wait(&status)等價(jià)于waitpid(-1,&status,0)
疑問(wèn):如果被設(shè)置為非阻塞,父進(jìn)程先于子進(jìn)程結(jié)束,子進(jìn)程變?yōu)楣逻M(jìn)程?由init調(diào)用wait回收?
筆記參考: https://www.cnblogs.com/king-77024128/articles/2684317.html
https://www.cnblogs.com/leijiangtao/p/4483009.html
標(biāo)簽:status,基礎(chǔ),void,pid,exit,Linux,進(jìn)程,include
來(lái)源: https://www.cnblogs.com/ptfe/p/10972475.html
總結(jié)
以上是生活随笔為你收集整理的linux wait 子孙进程,Linux-进程基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Qt creator5.7 OpenCV
- 下一篇: 下一步linux命令bzip,linux