博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

组ID,会话ID 进程间的关系

Posted on 2016-03-23 16:16  bw_0927  阅读(568)  评论(0)    收藏  举报

http://www.zyfforlinux.cc/2014/11/20/%E8%BF%9B%E7%A8%8B%E9%97%B4%E5%85%B3%E7%B3%BB/

 

进程组的概念

每一个进程除了有一个进程ID之外,还属于一个进程组,进程组通常是一个或多个进程的集合。这些进程通常是与一个作业相关的。
例如:
ps axu|grep bash|wc -l 这是三个进程,他们直接通过管道传递数据,为了是完成一个作业,对于这个整体来说是一个进程组
其中ps进程是进程组的组长进程。进程组也是由一个PID来标识进程组的,通过使用PGID来标识,然后这个PGID==进程组组长进程的PID的
使用下面的这个命令来验证这一事实:

1
2
3
4
5
6
[root@localhost common]# ps -o pid,ppid,pgid,sid,comm|more
PID PPID PGID SID COMMAND
2445 2441 2445 2445 bash
3882 2445 3882 2445 ps
3883 2445 3882 2445 more
ps 是其中的第一个进程,也是这个进程组的组长进程,那么其PID==PGID==2882 more和ps是同一个进程组的,因为其PGID相同
1
2
3
4
5
6
7
8
9
下面这两个方法是用来设置和获取进程组的方法
#include <unistd.h>

int setpgid(pid_t pid, pid_t pgid);
如果pid等于pgid,那么pid就成为了其所属的进程组的组长进程,
如果pid等于0,则标识把当前进程设置为pgid的组长进程
如果pgid等于0,则使用pid作为目标pgid

pid_t getpgid(pid_t pid); //这个方法的使用很简单,这里不做介绍
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <unistd.h>
#include <stdio.h>

int main()
{
printf("%d\n",getpgid(getpid()));
while(1);
}
测试结果如下: a.out属于4082这个进程组的,并且是组长进程
[root@localhost ~]# ps -o pid,ppid,pgid,sid,comm a
PID PPID PGID SID COMMAND
1698 815 1698 1698 bash
2445 2441 2445 2445 bash
4082 2445 4082 2445 a.out
4087 4083 4087 4087 bash
4206 4087 4206 4087 ps

会话的概念

会话就是一些有关联的进程组的集合,

1
2
3
4
5
6
7
[root@localhost ~]#  ps -o pid,ppid,pgid,sid,comm|more
PID PPID PGID SID COMMAND
4087 4083 4087 4087 bash
4521 4087 4521 4087 ps
4522 4087 4521 4087 more
再次使用这个例子,ps 和more进程是一个进程组,bash进程属于另外一个进程组,bash执行了ps和more进程,所以这两个进程组存在关联,属于一个会话。
其中SID代表这个会话的ID,从上面的结果可以看书,ps more bash是两个进程组的,但是都是一个会话的。会话ID,为首领进程组的组长进程的PID,
1
2
3
4
5
6
7
8
#include <unistd.h>
pid_t getsid(pid_t pid); //获取指定进程的sid
pid_t setsid(void);
1.不能由进程组的组长进程调用,否则会产生错误
2.非进程组的组长进程调用将会创建会话并且会产生下面的效果:
1.调用进程成为会话的首领,此时该进程是新会话的唯一成员
2.新建一个进程组,其PGID为其PID,该进程成为该组的组长进程
3.调用进程讲脱离终端(守护进程中常用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <unistd.h>
#include <stdio.h>

int main()
{
setsid();
perror("setsid error");
while(1);
}
setsid error: Operation not permitted
[root@localhost ~]# ps -o pid,ppid,pgid,sid,comm a
PID PPID PGID SID COMMAND
1698 815 1698 1698 bash
2445 2441 2445 2445 bash
4087 4083 4087 4087 bash
4960 2445 4960 2445 a.out
4961 4087 4961 4087 ps

执行上面程序会出错,因为执行这个程序后,这个程序是一个进程组的组长进程,组长进程是无法调用setsid的,并且从上文我们知道这个程序和bash是属于一个会话的,
那么下面这个例子演示了通过子进程(子进程和父进程是属于同一个进程组,但是子进程不是组长进程)

#include <unistd.h>
#include <stdio.h>

int main()
{
if(fork > 0)
//父进程等待
while(1);
else{
//子进程,创建会话,并创建一个新的进程组成为组长进程
setsid();
while(1)
}
}

PID PPID PGID SID COMMAND
5070 2445 5070 2445 a.out
5071 5070 5071 5071 a.out
最下面是a.out是子进程,上面的a.out是父进程,可以通过ppid来验证,父子进程已经不属于一个进程组了,并且也不属于一个会话进程,并且子进程成为了新的进程组的组长进程
完全符上面关于setsid的功能描述。

进程之间的关系

下面是bash进程fork出ps 和more进程执行,之间的进程间关系。