进程组,作业,会话
1进程组
每个进程除了有一个进程ID之外,还属于一个进程组.进程组是一个或者多个进程的集合.
通常他们与同一作业相关联,可以接受来自同一终端的各种信号.每个进程组有一个唯一的进程组ID,每个进程组都可以有一个组长进程.标识为:其进程组ID等于其进程ID
组长可以创建一个进程组,创建其中的进程,然后终止.只要组内有进程,则该进程就存在,与组长存亡无关
2作业
Shell分前后台控制的不是进程而是作业(Job)或者进程组(Process Group).一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成.shell可以运行一个前台作业和任意多个后台作业,这称为作业控制
作业与进程组的区别:如果作业中的某个进程创建了子进程,那么子进程不属于作业.而作业运行结束,shell就将自己提到前台,如果原先的前台进程还存在(子进程),他就自动变为后台进程组
3会话
会话是一个或者多个进程组的集合
一个会话可以有一个控制终端.也即是登录到其上的终端设备.
建立与控制终端连接的会话称为控制进程
一个会话应该包括一个控制进程(会话首进程),一个前台进程组和任意后台进程组
内核可以发送响应的信号给前台进程组中的所有进程
终端
unix系统中,用户通过终端登录到系统后得到一个shell进程.这个终端成为shell的控制终端,控制终端是保存在pcb中的信息,而fork会复制pcb信息,所以由当前shell启动的其他进程的控制终端也是这个终端
每个进程都可以通过访问/dev/tty访问他的控制终端.
ttyname函数可以由文件描述符查处对应的文件名
#include#includeint main(int argc, char const *argv[])
{
printf("fd: %d ->%s\n",0, ttyname(0));
printf("fd: %d ->%s\n",1, ttyname(1));
printf("fd: %d ->%s\n",2, ttyname(2));
return 0;
}
不同的终端运行结果
终端登录过程
可以通过Ctrl+Alt+F1~F6切换字符终端,相当于6个虚拟终端设备.对应/dev/tty1-6
tty0表示当前虚拟终端.
系统对终端输入的处理流程一般为
用户输入字符通过内核系统->终端设备驱动(字符解释)-->输出到终端
对于Ctrl+c等字符,不会被用户程序read到,而是被线路规程截获,解释为SIGINT信号给前台进程.
终端登录过程:
1.系统启动,init进程根据配置文件/etc/inittab确定需要打开哪些终端.
2.getty根据命令行参数打开终端设备作为他的控制终端,定位0,1,2描述符到终端.等待用户输入账户.
用户输入帐号后,getty任务完成,再执行login程序
execle("/bin/login","login", "-p",username,NULL,envp);
3login程序提示用户输入密码,如果不正确,login终止,init重新fork/exec一个getty进程.如果争取,login程序设置环境变量,设置当前工作目录为该进程的主目录,然后执行shell:
execl("/bin/bash","-bash",NULL);
getty--exec--login--bash,同一个进程执行,终端没有变.
作业控制
1.sessiion(会话)与进程组
启动一个终端也就是启动一个会话,一个会话中可以包含多个作业,每个作业对应一个初始进程组,如果进程组自己内部产生子进程,那么该进程非属于进程组,但不属于作业
注:截图中,我们关注PID进程id,PPID父进程id,PGID进程组id,SID会话(session leader)id
可以看到,所有进程的sid都是4414,等于第一个bash的id,这就是他们的会话id,
作业id等于组idPGID
lang@liang:~$ ps -o pid,ppid,pgid,session,tpgid,comm,wchan
PID PPID PGID SESS TPGID COMMAND WCHAN
4414 3980 4414 4414 4629 bash wait
4460 4414 4460 4414 4629 bash wait
4550 4460 4550 4414 4629 bash wait
4560 4550 4560 4414 4629 bash wait
4629 4560 4629 4414 4629 ps -
可以看到,TPGID为4629,也就是ps命令作为topgid(前台进程)其他进程切换至后台等待
jobs命令查看当前执行作业
bg将前台作业移动到后台
fg将后台作业移动到前台
lang@liang:~/linux$ jobs
[2]+ 运行中 sleep 299 &
lang@liang:~/linux$ sleep 100 &
[3] 4673
lang@liang:~/linux$ jobs
[2]- 运行中 sleep 299 &
[3]+ 运行中 sleep 100 &
lang@liang:~/linux$ fg 3
sleep 100
^C
lang@liang:~/linux$ jobs
[2]+ 运行中 sleep 299 &
守护进程
守护进程也叫精灵进程daemon.是运行在后台的一种特殊进程.
独立于控制终端
周期性执行任务或者等待事件发生.
不能直接和用户交互,系统服务进程不受洪湖登录注销影响,他们一直在运行,叫做守护进程
守护进程采用d结尾名字,表示daemon
创建守护进程最关键一步setsid,创建会话,成为会话首进程.
成功返回时:
1.创建一个新的session,当前进程成为session leader,当前进程id就是session的 id
2.创建一个新的进程组,当前进程成为进程组leader,....
3如果当前进程原本有一个控制终端,则失去这个终端, 成为一个没有控制终端的进程.失去(原本的终端仍然打开,仍然可以读写,但只是一个普通的打开文件而已.)
创建守护进程
1.调用umask将文件模式创建屏蔽字设置为0
2.调用fork,父进程退出(让shell以为程序结束,shell作为前台进程;;保证子进程是一个进程组的组长)
3.调用setsid创建一个新会话.(导致,1新会话首进程,2称为进程组长,3调用进程没有控制终端(再次fork保证daemon之后不会打开tty设备))
4.将当前工作目录更改为跟目录
5.关闭不需要的文件描述符
6忽略SIGCHLD信号
或者调用unix标准函数
daemon(0,0);