linux中的进程组与会话

阅读 0

09-23 21:00

1.前言

    linux中平时也不怎么用线程组、会话,但是每次看内核代码时老遇到这个,就觉得很烦,所以花点时间看一下进程组和会话。

2.作业控制

    谈到进程组和会话,首先要了解一下什么是作业控制(job control),进程组和会话主要是给作业(job)用的。 作业:用户通过shell提交的一个任务或者命令的执行实例,是一个或多个进程的集合,由shell管理,每个作业有一个唯一的作业ID(通常用数字表示,如[1]),用户可以使用作业控制命令来管理作业,如查看、暂停、恢复、前后台切换等。可以认为内核看到的是进程,用户看到的是作业。 一个作业通常对应一个进程,但一个作业也可能包括多个进程,例如

  • 单作业单进程:sleep 100
  • 单作业多进程:cat file.txt | grep key | wc -l,这3个进程位于同一个进程组

作业分为多种形式,包括

  • 前台作业:vi test.txt
  • 后台作业:sleep 300 &
  • 挂起作业:通过ctrl+z暂停的前台作业,暂停执行,但未终止

作业控制的常用命令

  • jobs:列出作业
  • fg [%job_id]:将后台或者挂起作业切换到前台
  • bg [%job_id]:将已暂停作业在后台执行
  • kill [%job_id]:终止指定作业,注意,id带%是作业,id不带%是停止进程

作业相关的其他信息

  • 管理进程组:为方便统一管理,shell会将一个作业中的所有进程放入同一个进程组(process group),通常使用作业中的第一个进程的pid作为pgid
  • 守护进程:可以理解为一种特殊的后台作业,脱离终端独立运行。通常会调用setsid()来创建新的会话(session)并成为新的进程组组长,从而脱离控制终端
  • 控制终端与前后台:一个终端同一时间只能有一个前台进程组接受输入(例如scanf)和信号(例如ctrl+c)。当使用fg命令将作业切换到前台时,shell会调用tcsetpgrp()函数,将中断的前台进程组设置为该作业的进程组ID

注意

  • 这里说的同一时间只能有一个前台进程组接受输入和信号,并不包含输出。也就是前台、后台进程都能往终端上通过echo输出。
  • 可以使用stty tostop禁止后台作业向终端输出,如果后台作业尝试向终端输出,内核会向其发送SIGTTOU信号,此信号默认暂停该后台作业。使用stty -tostop取消此设置,允许后台进程写终端。
  • SIGTTIN:后台进程尝试从控制终端读取数据时触发,默认行为是暂停进程
  • SIGTTOU:后台进程尝试向控制终端写入数据时触发,默认行为是暂停进程

3.什么是进程组

Process Group,是一个进程或者多个进程的集合。 引入进程组的原因:方便对一组进程进行控制,最主要的应用场景就是作业控制(job control) PGID与组长进程:进程组ID(PGID)在数值上等于该进程组中组长进程(group leader)的进程ID(pid) 理解进程组,我觉得应该从系统调用开始,哪些系统调用会以pgid为参数。包括:

  • setpgid/getpgid:设置/获取pgid
  • kill/killpg:向进程组发信号
  • waitpid:等待特定进程组中的任何一个子进程状态发生变化
  • tcsetpgrp:设置指定终端的前台进程组

所以综合来看,进程组主要就是作业控制会用到的几个功能。

4.会话

一次登录通常对应一个会话(session),该会话可能会关联一个控制终端。终端打开到终端关闭,这整个过程就是一个会话。会话的首进程(通常是shell)负责管理这个会话内的所有活动。

理解进程组,可以看看哪些系统调用跟会话相关,以及会话的一些特性。包括:

  • tcsetpgrp/tcgetpgrp:设置/查询指定终端的前台进程组
  • setsid:创建一个新的会话,并使调用进程成为新会话的首进程和新的进程组组长。彻底与原会话脱离关系,不再接收来自终端的中断信号(如果ctrl+c产生的SIGINT)或者挂起信号(SIGTSTP),也不会因为终端断开而收到SIGHUP信号而退出
  • getsid:获取指定进程的会话ID(sid)
  • 会话与进程组:一个会话包含一个或多个进程组,一个进程组包含一个或多个进程。一个会话最多只能有一个控制终端和一个前台进程组。前台进程组可以接收来自终端的输入(如键盘事件)和信号(如ctrl+c产生的SIGINT),后台进程默认只能向终端输出。
  • 会话中的SIGHUP信号:当会话关闭时,shell向前后台进程发出SIGHUP信号。

注意

  • 如果是nohup方式启动的,会忽略SIGHUP信号,不会退出
  • 如果使用了setsid(),已经完全脱离了原有会话,不会退出
  • 是否退出还会受到bash的hupnoexit配置影响,默认值是off。如果为on,bash才会向子进程发出SIGHUP信号。查询方法shopt | grep hupnoexit。设置方法:shopt -s hupnoexit(开启)/shopt -u hupnoexit(关闭)

5.查询进程组id和会话id

ps -wweo pid,ppid,pgid,sid,tty,comm

精彩评论(0)

0 0 举报