前言
子進(jìn)程退出的時(shí)候宵呛,父進(jìn)程能夠收到子進(jìn)程退出的信號(hào),便于管理夕凝,但是有時(shí)候又需要在父進(jìn)程退出的時(shí)候宝穗,子進(jìn)程也退出,該怎么辦呢码秉?
父進(jìn)程退出時(shí)逮矛,子進(jìn)程會(huì)如何?
一般情況下转砖,父進(jìn)程退出后须鼎,是不會(huì)通知子進(jìn)程的,這個(gè)時(shí)候子進(jìn)程會(huì)成為孤兒進(jìn)程府蔗,最終被init進(jìn)程收養(yǎng)晋控。我們先來看一下這種情況。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
//fork一個(gè)進(jìn)程
pid = fork();
//創(chuàng)建失敗
if (pid < 0)
{
perror("fork error:");
exit(1);
}
//子進(jìn)程
if (pid == 0)
{
printf("child process.\n");
printf("child pid:%d,parent pid:%d\n",getpid(),getppid());
printf("sleep 10 seconds.\n");
//sleep一段時(shí)間姓赤,讓父進(jìn)程先退出赡译,為了便于觀察,sleep 10s
sleep(10);
printf("now child pid: %d parent pid:%d\n",getpid(),getppid());
}
//父進(jìn)程
else
{
printf("parent process.\n");
sleep(1);
}
return 0;
}
在這個(gè)程序中不铆,我們?yōu)榱俗尭高M(jìn)程先退出蝌焚,子進(jìn)程sleep了10秒。
運(yùn)行結(jié)果如下:
parent process.
child process.
child pid:17433,parent pid:17432
sleep 10 seconds.
now child pid: 17433 parent pid:1658
從結(jié)果中可以看到狂男,一開始子進(jìn)程17433的父進(jìn)程id是17432综看,但是在10秒后,它的父進(jìn)程變成了1658岖食。1685是什么進(jìn)程呢?
$ ls -al /proc/1658/exe
/proc/1658/exe -> /sbin/upstart
由于我使用的環(huán)境是帶有圖形界面的ubuntu系統(tǒng)舞吭,所以最終并不是被我們所熟知的init進(jìn)程收養(yǎng)泡垃,而是被一個(gè)名為/sbin/upstart的進(jìn)程所收養(yǎng)析珊。另外還可以觀察到,該進(jìn)程也是其他系統(tǒng)進(jìn)程的父進(jìn)程蔑穴。
如何確保父進(jìn)程退出的同時(shí)忠寻,子進(jìn)程也退出?
既然如此存和,如何確保父進(jìn)程退出的同時(shí)奕剃,子進(jìn)程也退出呢?或許我們可以在子進(jìn)程和父進(jìn)程之間建立通信管道捐腿,一旦通信異常纵朋,則認(rèn)為父進(jìn)程退出,子進(jìn)程自己也回收資源退出茄袖。但是這樣做總覺得不是很正經(jīng)操软。有沒有已有的函數(shù)幫我們做這件事呢?prctl函數(shù)可以幫助我們宪祥。第一個(gè)參數(shù)中聂薪,有一個(gè)選項(xiàng),叫做PR_GET_PDEATHSIG:
PR_SET_PDEATHSIG (since Linux 2.1.57)
Set the parent death signal of the calling process to arg2 (either a signal value in the range 1..maxsig, or 0 to clear).
This is the signal that the calling process will get when its parent dies. This value is cleared for the child of a fork(2)
and (since Linux 2.4.36 / 2.6.23) when executing a set-user-ID or set-group-ID binary, or a binary that has associated capa‐
bilities (see capabilities(7)). This value is preserved across execve(2).
內(nèi)容很多蝗羊,主要意思為:設(shè)置一個(gè)信號(hào)藏澳,當(dāng)父進(jìn)程退出的時(shí)候,子進(jìn)程將會(huì)收到該信號(hào)耀找。
那么根據(jù)這個(gè)翔悠,我們完全可以在父進(jìn)程退出時(shí),也給子進(jìn)程一個(gè)退出的信號(hào)涯呻。程序代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <signal.h>
int main(void)
{
pid_t pid;
//fork一個(gè)進(jìn)程
pid = fork();
//創(chuàng)建失敗
if (pid < 0)
{
perror("fork error:");
exit(1);
}
//子進(jìn)程
if (pid == 0)
{
/*父進(jìn)程退出時(shí)凉驻,會(huì)收到SIGKILL信號(hào)*/
prctl(PR_SET_PDEATHSIG,SIGKILL);
printf("child process.\n");
printf("child pid:%d,parent pid:%d\n",getpid(),getppid());
printf("sleep 10 seconds.\n");
//sleep一段時(shí)間,讓父進(jìn)程先退出复罐,為了便于觀察涝登,sleep 10s
sleep(10);
printf("now child pid: %d parent pid:%d\n",getpid(),getppid());
}
//父進(jìn)程
else
{
printf("parent process.\n");
sleep(1);
}
return 0;
}
運(yùn)行結(jié)果:
parent process.
child process.
child pid:17625,parent pid:17624
sleep 10 seconds.
可以看到,由于加入了
prctl(PR_SET_PDEATHSIG,SIGKILL);
在父進(jìn)程退出時(shí)效诅,子進(jìn)程將會(huì)收到SIGKILL信號(hào)胀滚,而進(jìn)程收到該信號(hào)的默認(rèn)動(dòng)作則是退出。因而最后不會(huì)看到它成為孤兒進(jìn)程乱投,被其他進(jìn)程所收養(yǎng)咽笼。需要注意的是,該函數(shù)并非所有系統(tǒng)都支持戚炫。
總結(jié)
有些情況下剑刑,我們常常需要父子進(jìn)程共存亡,子進(jìn)程退出時(shí),父進(jìn)程可以通過wait捕捉子進(jìn)程的退出狀態(tài)施掏,但是父進(jìn)程退出時(shí)钮惠,子進(jìn)程卻難以得知。因此七芭,在最初fork子進(jìn)程的時(shí)候素挽,便表明了,當(dāng)父進(jìn)程退出的時(shí)候狸驳,子進(jìn)程收到SIGKILL信號(hào)预明,最終也退出。以此達(dá)到同生共死的目的耙箍。當(dāng)然也可以發(fā)送其他信號(hào)撰糠,由子進(jìn)程捕獲該信號(hào)并做后續(xù)處理。
練習(xí)
嘗試將上面的代碼在非圖形界面的linux操作系統(tǒng)中運(yùn)行究西,看看最終被收養(yǎng)的是否為init進(jìn)程窗慎。
交流
雖然本文方法可行,但并不適用于所有操作系統(tǒng)卤材,你有什么更好的辦法解決上面的問題遮斥?
微信公眾號(hào)【編程珠璣】:專注但不限于分享計(jì)算機(jī)編程基礎(chǔ),Linux扇丛,C語(yǔ)言术吗,C++,算法帆精,數(shù)據(jù)庫(kù)等編程相關(guān)[原創(chuàng)]技術(shù)文章较屿,號(hào)內(nèi)包含大量經(jīng)典電子書和視頻學(xué)習(xí)資源。歡迎一起交流學(xué)習(xí)卓练,一起修煉計(jì)算機(jī)“內(nèi)功”隘蝎,知其然,更知其所以然襟企。