posix用一个session的概念来描述一次用户的登录以及该用户在此次登录后的操作,然后用作业的概念描述不同操作的内容,最后才用进程的概念描述不同操作中某一个具体的工作;其次,unix最初将所有的进程组织成了树的形式,这样就便于追踪每个进程也便于管理,有了上述两个前提事情就很明白了,一切都是为了便于管理,一切都是为了登录用户的安全,即此次登录用户的作业是不能被下个登录用户所控制的,即使它们的用户名一致也是不行的,因此所谓的孤儿进程组简单点说就是脱离了创造它的session控制的,离开其session眼线的进程组,unix中怎样控制进程,怎样证明是否在自己的眼线内,那就是树形结构了,只要处于以自己为根的子树的进程就是自己眼线内的进程,这个进程就是受到保护的,有权操作的,而在别的树枝上的进程原则上是触动不得的,unix中建立进程使用fork,自然地这么一“叉子”就形成了自己的一个树枝,当然在自己眼线了,一般对于登录用户而言一个会话起始于一次login之后的shell,只要该用户不logout,在该终端的shell上执行的所有的非守护进程都是该shell的后代进程,因此它们组成一个会话,全部在shell的眼线中,一个会话终止于会话首长的death。现在考虑一下终端上的shell退出后的情景,按照规定,该终端上所有的进程都过继给了别的进程,大多数情况是init进程,然后紧接着另外一个用户登录了这个终端或者知道前一个登录用户密钥的另一个有不好念头的人登录了该终端,当然为其启动的shell创建了一个新的session,由于之前登录的用户已退出,现在登录的用户由于之前用户的进程组都成了孤儿进程组,所以它再有恶意也不能控制它们了,那些孤儿进程组中的成员要么继续安全的运行,要么被shell退出时发出的SIGHUP信号杀死。
1、会话内的进程按照树的形式进行管理,会话进程就是树根,缺省的退出动作是,关闭所有的子进程
ps -ax -o pid,ppid,pgrp,session,tpgid,comm
2、进程组ID可以改变,可以被进程组组长进程改变
函数 tcgetpgrp 和 tcsetpgrp
(1)tcgetpgrp 函数---获得前台进程组ID
(2)tcsetpgrp 函数---设置前台进程组ID
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t group1,group2;
//创建进程组1,父进程作为组长进程
setpgid(getpid(), getpid());
group1 = getpgid(getpid());
pid_t pid;
int i = 0;
for(; i < 3; i++) {
pid = fork();
if(pid < 0) {
perror("fork error");
exit(1);
} else if(pid > 0) {
if(i == 0) {
setpgid(pid, pid);
group2 = getpgid(pid);
}
if(i == 1) {
setpgid(pid, group2);
}
if(i == 2) {
setpgid(pid, group1);
}
} else {
if(i == 0) {
setpgid(getpid(), getpid());
group2 = getpgid(getpid());
}
if(i == 1) {
setpgid(getpid(), group2);
}
if(i == 2) {
setpgid(getpid(), group1);
}
break;
}
}
printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid(0));
pause();
exit(0);
}