在掌握会话的相关概念后,本篇完成一个创建会话的实例。

1. 目标

创建一个新会话,该会话中只有一个进程,就是创建该会话的进程。

2. 思路

创建会话的一个必要条件就是创建会话的进程不能是进程组组长。

这样做的理由是:假设该进程是进程组组长,创建完该会话后,该进程成为了其它会话中的 session leader。然而,其组员(如果存在的话)仍然存在于原来的会话中,这将导致同一个进程组中的进程处在不同会话中,显然这是不允许的。

直接在 bash 中执行进程,默认情况下,bash 会将该进程设置为进程组组长。

所以为了防止进程是进程组组长,有两种做法:一、将你的进程加入到当前会话中的其它组中;二、让你的进程 fork 出一个子进程,再 kill 掉父进程(不 kill 也没关系)。

第一种做法通常不太适合,因为你并不知道当前会话中有哪些组;其次,你怎么能随便把你的进程加到其它不相干的组呢?

所以这里就只有第二种做法了。

3. 程序清单

  • 代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
pid_t sid, pid;
pid = fork();
if (pid == 0) {
// 子进程不可能是进程组组长,可以让其创建新的会话,
// 同时它成为 session leader, group leader

// 先查看子进程从属于哪个会话
sid = getsid(getpid());
printf("sid = %d\n", sid);

// 让子进程创建新会话
sid = setsid();
if (sid < 0) {
perror("setsid");
}
// 查看子进程当前从属于哪个会话
printf("sid = %d\n", sid);
}

while(1) sleep(1);
return 0;
}

注意,上面的程序并没有 kill 掉父进程,这不是必须的。但是通常会 kill 掉,因为父进程已经没什么用了,除非你另作它用。

  • 编译和运行
$ gcc session.c -o session
$ ./session
  • 运行结果


68-会话(创建会话)_session


图1 session 进程运行的结果


通过使用命令 ​​ps ajx | sed -n '1p;/\/session$/p;/bash/p;/ps ajx/p'​​ 可以查看当前相关的会话。


68-会话(创建会话)_linux_02


图2 通过命令查看会话


图 2 中一共显示了 3 个会话,分别是 2874、2294、2925.

我们理一下这些会话之间的关系:

|- session 2874
|- group 2874
|- process 2874 [./session](session leader, group leader)
|- session 2294
|- group 2294
|- process 2294 [-bash](session leader, group leader)
|- group 2873
|- process 2873 [./session](group leader)
|- session 2925
|- group 2925
|- process 2925 [-bash](session leader, group leader)
|- group 3414
|- process 3414 [ps ajx](group leader)
|- process 3415

从上面的树型图可以很清晰的理清各个会话、进程组以及进程间的关系。

进程 2874 就是我们 fork 出来的子进程,它创建了一个新的会话 2874,同时任该会话的 session leader,同时也是进程组的组长。注意到进程 2874 已经脱离的终端了,在图 2 中的 TTY 一栏显示的是一个问号。

在会话 2294 中,进程 2294 是 session leader,也就是 bash 进程,我们执行 ./sesion 程序时,就是在这个 bash 中。其中,父进程 2873 仍然还在该会话中。

会话 2925 的 session leader 是 bash 2925 进程,也就是是我们执行命令​​ps ajx | sed -n '1p;/\/session$/p;/bash/p;/ps ajx/p'​​的那个地方,该会话中有两个进程组,其中一个进程组就只有 bash 进程组自己,另一个进程组,就是我们执行的命令,该进程组中有两个进程,分别是 ps 和 sed,而 ps 是该进程组的组长。

4. 总结

  • 理解会话
  • 掌握创建会话的方法
  • 理解进程组组长为什么不能创建新会话

练习1:完成本文中的实验,分析进程间关系。
练习2:直接关闭掉执行 ./sesion 程序的终端,再使用 ps 命令查看结果。