关于session和shell:
常见的session一般是shell session,在终端中只有一个session,当我们打开一个新的终端时,总会创建一个新session,session由一个或多个进程组组成,一般情况下shell进程当作session的领头进程。领头进程的PID当作seeesion的SID。session中的每个进程组被称为一个job。
关于job(任务):
执行一个命令会创建一个或多个进程,这些进程共属于一个进程组,每个进程组有一个group leader,group leader的pid就是进程组的id,通过ps命令可以查看进程的进程组id:ps -o pgid。
通过管道连接的进程属于相同的进程组,子进程会继承父进程的进程组和SID。(我们知道命令进程都是通过shell进程fork生成子进程执行的,那么一个session中是不是只有一个进程组呢?)
(答案:由shell进程fork出的子进程本来具有和shell相同的session、进程组和控制终端,但是shell调用setpgid函数将作业中的某个子进程指定为一个新进程组的group leader,然后调用setpgid将该作业中的其它子进程也转移到这个进程组中。如果这个进程组需要在前台运行,就调用 tcsetpgrp函数将它设置为前台进程组,由于一个session只能有一个前台进程组,所以shell所在的进程组就自动变成后台进程组。)
一个session同时只能有一个前台job,其余的都是后台job,每个session连接一个控制终端(control terminal)。控制终端的输入会被发送给前台job,前台job的标准输出也会发送给控制终端,同时由控制终端产生的信号也会传递给前台job。
将进程放入不同的session的唯一方法是:setsid使其成为新session的领头进程,同时本进程会被放入一个新的进程组中。
关于control terminal(控制终端):
控制终端是进程的一个属性,子进程会从父进程继承控制终端,所以一个session中的所有进程都会从领头进程处继承控制终端属性。
将多个进程放到一个进程组的主要目的是便于管理,可以向同一个进程组发送信号。
关于kill:
kill命令默认向进程发送SIGTERM信号,但是SIGTERM信号可以被进程设置为忽略,因此无法关闭这些进程。这时候使用kill -SIGKILL (kill -9) PID发送SIGKILL命令,这个信号是不能被忽略的。
关于session消亡:
当session中所有的进程都退出时session就消亡了,正常的消亡过程:内核发现终端关闭,发送SIGHUP信号给session领头进程,session领头进程接收SIGHUP信号,并将该信号发送给session中的每一个进程,SIGHUP信号的默认处理方法是结束进程。
内核发现终端关闭:可能是远程登陆时网络断开,或者手动x掉了终端窗口。
关于守护进程:
守护进程是一种独立于控制终端的后台进程,无法通过控制终端和用户进行交互,守护进程是一种长时间执行的进程,比如说服务器程序。通过调用setsid函数让一个进程成为守护进程(创建新session,放弃终端,创建新进程组)。
关于setsid函数:
调用setstd函数会创建一个新的session,并且该进程成为session的领头进程,而且该进程会以自己的PID创建一个新的进程组。调用这个函数的进程不允许是某一个session的领头进程。(通过fork避免这个问题)setsid会放弃当前的控制终端。
ps -x参数可以显示所有与终端无关的进程
-a 显示所有与终端相关的进程
-u 以用户为中心组织进程信息显示