threads, processes, process groups and sessions

来源:互联网 发布:超链接调用js 编辑:程序博客网 时间:2024/04/29 09:42

主要是相关知识的初步整理以及自己的理解。

session > process group > process > thread
ps fj可以查看进程的PID,PPID,PGID,SID信息

I、线程(thread)

  cpu调度的基业单位,每个thread代表一条执行流

II、进程(process)

  系统资源分配的基业单位,主要内核结构体为task_struct

Zombie状态

  子进程退出之后可以通过信号告诉父进程这一事件,但是信号传递的信息很有限;Zombie机制使得子进程传递更多的信息(结束原因等)给父进程,父进程通过wait系统调用来获取这些信息。

III、会话(session)

1. 引入会话的背景

From Linux Application Development, 2nd Edition 10.6.1

  当用户退出登陆时,内核需要结束该用户的所有进程,否则系统中可能会残留很多等待使用控制终端的进程(由于终端资源已被释放,所以他们的请求永远不会被满足),为了简化这项任务抽象出会话的概念。

  创建会话的第一个进程为session leader(一般为shell); 默认情况下,session leader创建的子进程和自己属于同一会话中,当然子进程可以新创建单独的会话。会话一般代表着用户的一次登陆,一次登陆即创建一个会话

2. 控制终端

A terminal can be the controlling terminal for only one session at a time.

2.1. 为了提供人机交互,每个会话可以和一个终端关联用于进程的输入输出(一个终端只能同时被一个会话独占使用),这个终端被称为控制终端; 控制终端一般由login进程分配,可以是本地控制台console, 通过串口线连接的终端terminal, 伪终端pseudo terminal;

2.2. 如果会话有控制终端,那么控制终端文件描述符可以通过打开/dev/tty打开来获得,打开失败说明没有控制终端; 根据这个打开的文件描述符可以用tcgetsid获取与之关联的会话的标识sid;

III、进程组(process group)

1.引入进程组的背景

From Glibc 28.1 Concepts of Job Control

  用户在shell中输入的一条命令(以回车为结束标识)可以对应多个进程,特别是使用管道符构造命令的时候; 由这条命令创建的所有进程一起被称作进程组或者作业(等同,下文不再区分地使用两者),进程组可以对这些进程进行跟踪。抽象出进程组这个概念的一个好处就是方便作业管理,因为作业控制的对象就是进程组。比如,你可以用一个Ctrl-C给前台进程组中的所有进程发送SIGINT信号。

说明:

  1.1. 进程组是一些相关联的进程的集合,该组中第一个被创建的进程被称为group leader,进程组的标识和group leader的进程ID相同;
  1.2. group leader退出后进程组依然存在,直到最后一个组成员退出;
  1.3. bash上的每条命令都会创建一个新的进程组(不支持作业控制的shell中,所有的进程都属于都一个进程组);

2. 前台进程组和后台进程组

  2.1 系统login进程调用用户在/etc/passwd中指定的login shell创建会话,login shell用于系统和用户之间的交互(常用的是bash,拥有作业控制的功能),bash的一项职责就是联合终端驱动程序一起来仲裁控制终端的使用权。
  2.2 当前正在使用控制终端的进程组被称为前台进程组,同一时刻只能有一个进程组使用控制终端; 剩余的进程组被统称为后台进程组tcgetpgrp(fd)系统调用可以用来获取正在使用控制终端fd的前台进程组;tcsetpgrp(fd, pgrp)可以用来设置前台进程组pgrp占用控制终端fd。
  2.3 前台进程组可以尽情的享用控制终端,而后台进程组使用控制终端会受到限制:后台进程组里的进程如果尝试读取终端,读取进程会收到SIGTTIN信号被停止,如果后台进程忽略该信号则会导致读取返回失败;同理,如果后台进程尝试向终端写入数据而且tostop标志被设置(tty -a查看当前配置,如果没有设置该选项,后台进程也是可以向终端输出的,只是会和前台的输出混在一起而已),写入进程会收到SIGTTOU信号被停止,如果后台进程忽略该信号则会导致写入返回失败。bash的另一项职责就是当有后台进程因读取控制终端而被停止时通知用户,并提供相应的手段让用户可以切换前后台进程组。

3. 孤儿进程组(Orphaned process groups)

3.1. 定义
如果一个进程组成员的父进程要么是本组的其它成员,要么不在本组所属的会话中。反过来说,如果一个进程组成员的父进程在同一会话的另一个组中,那么这个进程组就不是孤儿进程组。

说明:

  • 从定义中可以看出会话首进程所在的组一定是孤儿进程组,因为会话首进程是由属于另一个会话的Login进程所创建的;
  • 如果会话首进程bash退出,它的子进程被Init进程领养,会话中所有的进程组都变成了孤儿进程组,孤儿进程组会被强制和控制终端取消关联

3.2 定义理解

When a process group is orphaned, every process in that process group is sent a SIGHUP, which normally terminates the program. Programs that have chosen not to terminate on SIGHUP are sent a SIGCONT, which resumes any suspended processes. This sequence terminates most processes and makes sure that any processes that are left are able to run (are not suspended). Once a process has been orphaned, it is forcibly disassociated from its controlling terminal (to allow a new user to make use of that terminal). If programs that continue running try to access that terminal, those attempts result in errors, with errno set to EIO. The processes remain in the same session, and the session ID is not used for a new process ID until every program in that session has exited.

最简单的理解:孤儿进程组主要是为了终止不应该继续运行的进程(需要使用控制终端),恢复可以继续运行的进程(捕获了SIGHUP信号)

IV、挂断信号SIGHUP

保留原文,看完之后就知道为什么关闭putty之后所有的进程就被杀死了:P

When does kernel(terminal driver) send SIGHUP?

  • Kernel sends SIGHUP to controlling process:
    • for real (hardware) terminal: when disconnect is detected in a terminal driver, e.g. on hangup on modem line;
    • for pseudoterminal (pty): when last descriptor referencing master side of pty is closed, e.g. when you close terminal window.
  • Kernel sends SIGHUP to other process groups:
    • to foreground process group, when controling process terminates;
    • to orphaned process group, when it becomes orphaned and it has stopped members.

Typically, the controlling process is your shell. So, to sum up:

  • kernel sends SIGHUP to the shell when real or pseudoterminal is disconnected/closed;
  • kernel sends SIGHUP to foreground process group when the shell terminates;
  • kernel sends SIGHUP to orphaned process group if it contains stopped processes, kernel does not send SIGHUP to background process group if it contains no stopped processes.

When does bash send SIGHUP?

  • Bash sends SIGHUP to all jobs (foreground and background):
    • when it receives SIGHUP, and it is an interactive shell (and job control support is enabled at compile-time);
    • when it exits, it is an interactive login shell, and huponexit option is set (and job control support is enabled at compile-time).
Notes:
  • bash does not send SIGHUP to jobs removed from job list using disown;
  • processes started using nohup ignore SIGHUP.
    What about other shells?
    Usually, shells propagate SIGHUP. Generating SIGHUP at normal exit is less common.
其它:
  1. The process doesn’t get a HUP when its parent dies. It gets a HUP when it loses the connection to the controlling terminal or when it is explicitly sent a HUP. This happens for example when you logout of SSH. the shell itself can send a HUP to all its children when it exits. However, bash for example has huponexit set to false by default. This may well be what has changed.
  2. regardless of the huponexit option, when it receives a HUP the shell also sends a HUP to all its children.
  3. If a modem (or network) disconnect is detected by the terminal interface the hang-up signal is sent to the controlling process (the session leader).To further clarify, **the initial HUP is not sent by the shell,It is sent by the terminal driver. **Afterwards the shell “forwards” it to the children. So indeed, a HUP sent by the terminal driver can “cascade”.
  4. When a controlling process loses its terminal connection, the kernel sends it a SIGHUP signal to inform it of this fact.

V、相关数据结构

可能不是Linux中的实现,不过还是有一定的参考意义

related data struct

VI、参考文档

  1. Linux Application Development, 2nd Edition 10.6 Sessions and Process Groups
  2. APUE 9.10. Orphaned Process Groups
  3. http://stackoverflow.com/questions/32780706/does-linux-kill-background-processes-if-we-close-the-terminal-from-which-it-has
0 0