一个进程主要关系有: 会话组、进程组、父子进程关系等。
通常,在同一控制台下执行、运行的程序属于同一会话组;父子进程属于同一进程组;一个会话组可包含多个进程组。
守护进程(精灵进程),顾名思义,就像护花使者一个样在背后默默支持着他的花儿;也像父亲一直保卫着,守护着孩子们的成长,
当一个进程成为孤儿进程之后,再改变此孤儿进程的会话组、进程组,然后再赋予它特殊使命(在后台孜孜不倦的完成莫特定功能),就可以说此进程为守护进程。
一个普通进程成为守护进程的过程:
1.让普通进程的父进程先于它退出,此普通进程将被1号进程收养,成为孤儿进程;
2.用setpgid或setsid改变此孤儿进程关系;
当一个进程成为孤儿进程后,可以用 setpgid() 可以设置进程组ID为自己,但会话组不会变;
当一个进程成为孤儿进程后,用setsid设置会话组为自己,同时进程组也会变为自己;他的子进程也会跟随变动。
3.此时的进程程摆脱了原会话的控制;摆脱了原进程组的控制;摆脱了原控制终端的控制;
此时的进程即为守护进程,在后台运行,可以让它周期性的执行特殊任务。
下面这个程序是一个守护进程监控一个子进程,一旦这个子进程退出,守护进程会将它拉起。
//主程序
#include <unistd.h> #include <iostream.h> #include <signal.h> #include <sys/wait.h> void daemon() { pid_t pid; pid = fork(); if (pid < 0) { cout<<"fork failed."<<endl; return; } else if (pid == 0) { //由于在调用了fork函数时,子进程全盘拷贝了父进程的会话期、进程组、控制终端等,虽然父进程退出了,但会话期、进程组、控制终端等并没有改变,因此,这还不是真正意义上的独立开来,而setsid函数能够使进程完全独立出来,从而摆脱其他进程的控制。 //在子进程中调用setsid()后,子进程成为新会话首进程,且成为一个组长进程,其进程组id等于会话id setsid(); return; } else { //让其父进程立即终止,使得子进程能在init下运行;这种方法通常被称为“脱壳”。 exit(0); } } //拉起子进程 void run_sonprocess() { pid_t child_pid=fork(); if(child_pid<0) { cout<<"fork failed."<<endl; return; } else if(child_pid==0) { cout<<"begin run son process"<<endl; char path[50]="./son"; execlp(path,"son",(char*)0); } else { cout<<"I'm daemon"<<endl; } } void re_run(int) { int status; pid_t child_pid; child_pid=wait(&status); if(child_pid<0) return; else { cout<<"Warning: process "<<child_pid<<" is exit"<<endl; } //重新执行 run_sonprocess(); } int main() { signal(SIGCHLD, re_run); daemon(); run_sonprocess(); for(;;) ; return(0); }
//子程序
#include <iostream.h> int main() { for(int loop=0; loop<10; loop++) { cout<<"son process is running " <<loop<<endl; sleep(2); } return 1; }