Linux进程模型——会话和进程组

先放总结给没空看全文的人:

  • session(会话)是用户登录系统以后所需的context(上下文)
  • process group(进程组)是一组相关联的进程,用来方便信号量的分发
  • session退出以后所有隶属于该session的进程组都会收到hup信号而挂起,这样就有了控制进程生命周期的作用
  • tty可以作为输入输出设备被绑定到一个session上,bash就是这么干的
  • 子进程会继承父进程的session和process group,可以通过setsid建立新的session来脱离继承的sid,从而逃离旧session的生命周期
  • 当使用killpg将信号传递给进程组的时候,这个信号会被分发至进程组的每个进程。所以进程组可以方便对进程的控制

前述模型-父子进程

在日常的学习生活中,普通人接触较多的主要是parent-children进程模型。这是一个简单明了的编程模型:

  1. 父进程fork()以后产生一个子进程,子进程继承父进程的资源
  2. 子进程exec()点什么
  3. 假如子进程退出,那么父进程就得wait() / signal(SIGCHLD,SIG_IGN),否则子进程会变僵尸进程
  4. 假如父进程退出,那么子进程就会变成孤儿进程,然后被init收养

一个典型的父子进程模型的代码如下:

#include  <stdio.h>
#include  <sys/types.h>

void  ChildProcess(void);                /* child process prototype  */
void  ParentProcess(void);               /* parent process prototype */

void  main(void)
{
     pid_t  pid;
     signal(SIGCHLD,SIG_IGN);
     pid = fork();
     if (pid == 0)
          ChildProcess();
     else
          ParentProcess();
}

但是在多用户多终端下,简单的进程的父子进程模型难以描述复杂的进程关系,于是Linux在原有模型的基础上,引入了session(会话)和process group(进程组)的概念。

Linux进程模型

session

因为Linux是多用户系统,每个用户都需要和系统相对独立的进行交互,于是session的概念就被引入进来。当用户log in,然后打开bash的时候,会通过系统调用setsid建立一个session。session就是用户此次登录的context,可以方便的用来存储信息、控制会话、分配资源。比如,session就是tty(控制终端)绑定的对象。下面是ssh登录远端服务器时,关于session创建的例子:

  1. 首先列出参与的进程信息
UID        PID  PPID  PGID   SID  C STIME TTY          TIME CMD
root      1488     1  1488  1488  0  2017 ?        00:02:22 /usr/sbin/sshd -D
ubuntu   17132 17092 17092 17092  0 14:59 ?        00:00:00 sshd: ubuntu@pts/0
ubuntu   17135 17132 17135 17135  0 14:59 pts/0    00:00:00 -bash
ubuntu   17171 17135 17171 17135  0 15:00 pts/0    00:00:00 ps -ejf
  1. 服务端上守护进程sshd 1488监听到了client连接请求
  2. 守护进程fork一个子进程sshd: ubuntu 17132,来处理请求。可以看到这个子进程17132的SID与父进程1488不同,这里是通过系统调用setsid()建立了一个新的session
  3. 进程sshd 17132 forkexec了子进程bash作为交互界面,可以看到bash 17135又创建了一个新的session,并且绑定了一个虚拟控制终端(controlling terminal / tty)pts/0。至此我们终于可以通过sshd 17132pts/0输入交互信息了,这些输入最终会作为session 17135的stdin被bash接受并处理。
  4. 在bash中我们执行了ps -ejf查看进程信息,于是bash创建了一个子进程ps -ejf执行请求。可以看到子进程ps 17171拥有和bash相同的sidtty
  5. session 17135session leader也就是bash 17135退出的时候,在此session下的所有进程也会收到hup(挂断信号)而终止退出

因此,偷懒的守护进程代码是这样:

#include  <stdio.h>
#include  <sys/types.h>
#include <unistd.h>

void  ChildProcess(void);                /* child process prototype  */
void  ParentProcess(void);               /* parent process prototype */

void  main(void)
{
     pid_t  pid;
     signal(SIGCHLD,SIG_IGN);
     pid = fork();
     if (pid == 0)
     {
         setsid();  #守护进程建立新的session
         ChildProcess();
     }
     else
          exit();
}

首先可以发现本段代码相比父子进程模型多了setsid(),它的作用是建立新的session,sid就是当前进程的pid。当守护进程属于一个新的session以后,就会脱离父进程session的生命周期和tty,也就是说,daemon将不会因为父session关闭而被挂断,也不会将父tty作为标准输入输出。
然后,为什么这是偷懒的代码呢,因为严谨的daemon需要两次fork来产生。下面描述完进程组的以后会给出标准daemon创建例程。

Process Group

进程组的存在是为了方便对一组进程进行统一的管理。比如我们可以通过killpg向进程组传递信号量。或者方便利用job controll来进行前后台进程组的切换。
现在进程组的概念仍然比较抽象,以后有机会学到容器的虚拟化机理,应该能够深刻体会进程组的作用。

下面是double fork的示例代码:

fork();
if (pid == 0) {
  setsid();
  fork();
  if (pid == 0) {
    childProcess();
  }
}
exit();

double fork的原因主要有:

  • 如果只有一次fork,假如父进程并没有退出,而是需要继续运行其他代码,那么子进程daemon就不会被过继给init。在两次fork的情况下,第一个child process的作用只是用来产生daemon进程,fork完称以后可以直接exit,这样就能显式保证daemon在创建完成后就会被过继给init,而祖父进程仍然可以继续执行其他逻辑
  • 如果只有一次fork,那么daemon因为setsid,所以会是session leader。这意味着daemon将有权限将这个新创建的session绑定到tty上。而两次fork产生的daemon,因为第二个child process并没有setsid,所以并不是session leader,从而杜绝了这种情况发生 (这种说法来自stackoverflow,我目前并没有验证过)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容