赞
踩
命令:ps -ajx
输入ps -ajx 命令后
例如:cron 进程就是一个守护进程
进程组是一个或多个进程的集合。进程组由进程组ID(PGID)来唯一标识。每个进程组都有一个组长进程,进程组ID就是组长进程的进程号。
是一个或多个进程组的集合。
一般一个用户登录后新建一个会话(打开终端),每个会话也有一个ID来标识(SID)。登录后的第一个进程叫做会话领头进程(session leader),通常是一个shell/bash,即一个shell程序。对于会话领头进程,其PID=SID。
为什么是一个用户登录后新建一个会话呢?
一般取去公司上班,我们见不到服务器真机,而是公司为每个员工分配一个 用户名和密码,我们可以通过远程进行登录。这个时候我们就登录到了一个终端,因此说一个用户登录后新建一个会话。
$ ./a.out &
那么这个进程只能向终端打印内容,但是不能读取终端中的内容。注意:每个会话有且只有一个前台进程组,但会有0个或者多个后台进程组。
每个进程还有一个属性,终端进程组ID(TPGID),用来标识一个进程是否处于一个和终端相关的进程组中。
前台进程组中的进程的TPGID=PGID,
后台进程组的PGID≠TPGID(d一般前台进程组ID等于终端ID,而后台进程组ID不等于终端ID)。
若该进程和任何终端无关,其值为-1。
通过进程进程组PPID比较终端进程组ID来判断一个进程是属于前台进程组,还是后台进程组,还是与终端无关的进程。
该图说明,shell也只是一个程序,称为命令行解释器。用来解读终端发送给操作系统的命令。打开一个终端后,会首先启动一个shell进程。并且该终端会与这个shell进程关联起来。shell解读终端传输的命令,发送给操作系统,然后调用相关的系统调用,然后将结果再传递到终端上。
1)在终端中执行下述命令
2)重新开启一个终端,执行: ps -ajx
命令
3)观察第一个终端中两个进程的进程状态,结果如下图:
4)在第一个终端中按ctrl+z 再次观察结果
通过第一个实验结果可以看出:
保证祖父进程确认父进程已结束,且守护进程不是组长进程
并成为两者的首进程,此时刚创建的新会话还没有关联控制终端。
#include <unistd.h>
pid_t setsid(void);
//返回值:若成功,返回新的会话期ID;若出错,返回-1。
setsid函数的作用
注意:
如果该调用进程已经是一个进程组组长,则此函数返回出错。回想一下我们为了保证不处于这种情况我们是如何处理的?第一步,先调用fork,然后父进程终止,而子进程继续。因为子进程继承了父进程的进程组ID,而其进程ID是新分配的,两者不可能相等,这就保证了子进程不是一个进程组组长。
再新建一个进程,并且关闭第一子进程。这么做的目的是,避免第一子进程再次与终端产生联系(第一子进程是会话领头进程,当它与终端脱离联系后,它可以再通过某种方式再与终端建立联系。为了避免这种情况产生,所以再fork一个子进程,第二子进程不再是会话的领头进程,所以就完全与终端脱离联系了。)
守护进程一般随系统启动,工作目录不应继续使用继承的工作目录。
这一步也是必要的步骤。使用fork()创建的子进程继承了父进程的当前工作目录。由于在进程运行过程中,当前目录所在的文件系统(如“/mnt/usb”等)是不能卸载的,这对以后的使用会造成诸多的麻烦。因此,通常的做法是让“/”作为守护进程的当前工作目录,这样就可以避免上述问题(避免工作目录被卸载)。当然,如有特殊需要,也可以把当前工作目录换成其他的路径,如/tmp。改变工作目录的常见函数是chdir()。
守护进程不需要继承文件权限掩码。
进程从创建它的父进程那里继承了文件创建掩码。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0)。
不需要继承任何打开的文件描述符。
进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。
一般的关闭方法:
for(i=0;i<=getdtablesize();i++)
close(i);
#include <unistd.h>
int getdtablesize(void);
//返回:进程最多打开文件描述符的个数(1024)
#include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <linux/fs.h> int main() { //第一步:创建一个进程,使其父进程退出 pid_t pid = fork(); if( pid == -1 ) return -1; else if( pid != 0 ) exit( EXIT_SUCCESS ); else //第二步:守护进程创建新进程组和新会话 if( setsid() == -1 )//如果创建失败,返回 return -2; //第三步:设置工作目录 if( chdir( "/" ) == -1 )//设置错误的话返回 return -3; //第四步:重设文件权限掩码 umask( 0 ); //第五步:关闭文件描述符 for( int i = 0; i < getdtablesize(); i++ ) close( i ); //第六步:重定向标准流 open( "/dev/null", O_RDWR ); // 重定向stdin dup( 0 ); // 重定向stdout dup( 0 ); // 重定向stderr //守护进程的实际工作代码在此 return 0; }
重定向的原理:
所有的文件描述符都已经关闭,因此,第一个打开的是0号文件描述符,然后dup(0) 两次,是把0号代表的文件复制给1号2号文件描述符。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。