
本文共 2966 字,大约阅读时间需要 9 分钟。
僵死进程:在UNIX术语中,一个已经终止,但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放它仍然占用的资源)的进程成为 僵尸进程。
孤儿进程:如果父进程先退出,子进程还没有完成,那么此时子进程就会被托付给 init进程,此时该子进程的父进程就是 init进程(1号进程)。
守护进程:一般是指 Linux中的后台服务进程,它是一个生存周期较长的进程,如其父进程为init进程,通常独立于控制终端,即 不接受电脑用户的直接操作。守护进程是一个特殊的孤儿进程。
会话(session): 会话是一个或多个进程组的集合。通常一个会话开始于 用户登录,终止于用户退出,在此期间用户运行的所有进程都属于会话
进程组:每个进程除了有一个进程ID之外,还属于一个进程组。进程组是一个或多个进程的集合。每个进程组有一个组长进程,组长进程的进程ID等于进程组ID。
NAME setsid - creates a session and sets the process group ID创建会话,并设置进程组的IDSYNOPSIS #includepid_t setsid(void);
如果调用setsid()的进程不是一个进程组的组长进程,则 创建一个会话。即父进程不能调用setsid()创建会话,只能由子进程调用。调用setsid()的进程会成为 会话组长,以及 会成为当前新的进程组的组长。并且脱离控制终端。
setsid()用于创建一个新的会话,并有以下三个作用: 1 让进程摆脱原会话的控制 2 让进程摆脱原进程组的控制 3 让进程摆脱原控制终端的控制
守护进程:
1 后台服务程序 2 脱离控制终端,用户无法通过终端与守护进程交互,TTY == ? 3 长期,周期性的执行某任务,即父进程为init进程,即1号进程 4 不受用户登录,注销的影响 即不受当前会话控制那么,在创建守护进程时为什么要调用setsid函数呢?由于创建守护进程的第一步调用了fork函数来创建子进程,再将父进程退出。由于在调用了fork函数时,子进程全盘拷贝了父进程的会话期、进程组、控制终端等,虽然父进程退出了,但会话期、进程组、控制终端等并没有改变,因此,这还不是真正意义上的独立开来,而setsid函数能够使进程完全独立出来,从而摆脱其他进程的控制。
一个进程一定会父进程,但是守护进程有点不一样,一般子进程调用之后,按照之前的逻辑,子进程运行的时候,父进程会一直等待子进程运行完成 并释放资源,即 wait()收尸,但是守护进程就没有必要 wait()了,因为它运行的时间会很长,父进程以及父进程的父进程等等就没必要一直等待了,所以直接托付给init进程就好。
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ps axj PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND父进程ID : PPID进程ID : PID组进程ID : PGID会话ID : SID
实验:守护进程的创建
#include#include #include #include #include #include #include #define FILENAME "/tmp/out"static int craetdeamon(void){ pid_t pid; int fd; pid = fork(); if(pid < 0) { perror("fork()"); return -1; } if(pid > 0) //父进程结束 { printf("%d\n",getpid()); exit(0); } fd = open("/dev/null",O_RDWR); if(fd < 0) { perror("open()"); return -1; }//重定向 0 1 2 文件描述符 dup2(fd,0); dup2(fd,1); dup2(fd,2); if(fd > 2) { close(fd); }//创建守护进程 setsid(); chdir("/"); return 0;}int main(int argc,char* argv[]){ FILE* fp; int i; if(craetdeamon()) { exit(1); } fp = fopen(FILENAME,"w"); if(fp == NULL) { perror("fopen()"); exit(1); } for(i = 0; ;i++) { fprintf(fp,"%d\n",i); fflush(fp); sleep(1); } exit(0);}mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ps axj ... 1662 3141 3141 3141 ? -1 Ss 1000 0:00 ./a.out 2959 3188 3188 2959 pts/2 3188 R+ 1000 0:00 ps axj父进程是 1662 并不是init进程mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ps 1662 PID TTY STAT TIME COMMAND 1662 ? Ss 0:00 /sbin/upstart --usermhr@ubuntu:~/Desktop/xitongbiancheng/test$ mhr@ubuntu:~/Desktop/xitongbiancheng/test$ tail -f /tmp/out169316941695169616971698169917001701mhr@ubuntu:~/Desktop/xitongbiancheng/test$ kill 3141最后记得杀死 守护进程
发现此时守护进程的父进程 并不是init进程,后面得知 原来较新 ubuntu 使用 upstart进程 来替代的 init进程 收养孤儿进程。
之所以来重定向 0 1 2 三个文件描述符:
用fork函数新建的子进程会从父进程那里继承一些已经打开了的文件。守护进程已经与所属的控制终端失去了联系。因此从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如printf)输出的字符也不可能在终端上显示出来。所以,文件描述符为0、1和2 的3个文件(常说的输入、输出和报错)已经失去了存在的价值,也应被关闭或重定向。使用fork创建的子进程会继承父进程的工作目录,如果守护进程踩在某个设备上运行,而当设备卸载时,会出现异常,device is busy。通常做法是让让 根目录(“/”)作为守护进程的当前工作目录。可以避免上述问题。
chdir("/");发表评论
最新留言
关于作者
