进程间关系
几个基本概念
1、进程组
每个进程不仅有一个进程ID,还属于一个进程组。进程组是一个或者多个进程的集合。每个进程组拥有一个唯一的进程组ID。每个进程组可以有一个组长进程。组长进程的标识是,其进程组ID等于其进程ID。组长进程可以创建一个进程组,创建该组中的进程,然后终止。只要在某个进程组中一个进程存在,则改进程组就存在,这与其组长进程是否终止无关。
如上图,sleep了三个进程,分别sleep了100 200 300,从图中可以看见该三个进程的进程ID,和他们的进程组ID-PGID,可以看到他们的进程ID不同,但他们的进程组ID相同,其中sleep 100进程的进程ID和进程组ID相同,所以它就是该进程组的组长进程。图中S后有+表示是在前台运行。
如图,当我们使用kill -9 杀死了组长进程,该组进程依然存在。
查看进程信息命令ps:
- a:不仅列出当前用户的进程,也列出所有其他用户的进程
- x:表示不仅猎游控制终端的进程,也列出所有无控制终端的进程
- j:表示列出与作业控制相关的信息
ctrl + c可以一次终止前台进程组,它杀掉的不是杀的进程,而是整个作业。
2、作业
shell分前后台控制的不是进程而是作业和进程组。一个前台作业可以由多个进程组成,一个后台也可以由多个进程组成,shell可以运行一个前台作业和任意多个后台作业,这就称为作业控制。
作业和进程组、进程、线程之间的关系:
多个线程属于一个进程,多个进程属于一个进程组,多个进程组属于一个作业。
bash是一个独立的进程组,也是一个独立的作业。
如果作业中的某个进程又创建了子进程,则子进程不属于作业。
在前台新起作业,shell是无法运行的,因为他被提到了后台。但是如果前台进程退出,shell就又被提到了前台,所以可以继续接受用户输入。
3、会话
会话是一个或者多个进程组的集合。一个会话中,包括控制进程,一个前台进程组和任意后台进程组。
当我们使用ps查看进程信息时,SID就是会话ID,TTY表示终端。我们的会话首进程一般都是bash。
作业控制
作业控制的概念在作业那里提及过,就是shell可以同时运行一个前台作业和任意多个后台作业。
ctrl + z可以将进程提到后台。
& 可以将进程组放在后台执行
作业控制有关的几个信号:
fg 作业号:将作业放在前台
bg 作业号:将作业放在后台
jobs:可以查看当前有哪些作业
ctrl -z 向当前所有前台进程发SIGCONT:默认动作使进程停止
kill杀死一个进程会发SIGTERM信号:这个信号要等待进程准备继续执行之前处理,默认动作是终止进程
SIGTTIN:默认处理动作是使进程停止。
后台进程不能从终端下读数据。
守护进程
守护进程的概念
守护进程又被称为精灵进程,是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事情。Linux的大多数服务器就是用守护进程实现的,如ftp服务器,ssh服务器,Web服务器等,守护进程完成很多系统任务,如作业规划进程crond。
守护进程不受用户登录注销影响,它会一直运行。
在使用ps查看进程的时候TPGID一栏是-1的都是没有控制终端的进程,就是守护进程。
COMMAND一栏用[]括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,没有程序文件名和命令行,通常采用k靠头的名字,如kthreadd
init进程用于用户登录,udevd负责维护/dev目录下的设备文件,acpid负责电源管理,syslogd负责维护/var/log下的日志文件。
守护进程通常采用d结尾的名字。
创建守护进程
创建守护进程需要调用setsid函数创建一个新的会话,并成为Session Leader。
#include <unistd.h>
pid_t setsid(void);
//该函数调用成功返回新创建的会话ID(也就是当前进程的id),出错返回-1
注意:调用这个函数,当前进程不允许是进程组的组长,否则函数返回-1,也就是先fork在调用setsid。
成功调用该函数的结果:
- 创建一个新的会话,当前的进程成为Session Leader,当前进程组的id就是会话id。
- 创建一个新的进程组,当前进程为进程组的组长,当前的进程id就是进程组id
- 如果当前进程原本有一个控制终端任然是打开的,则它失去这个控制终端,成为一个没有控制终端的进程。
daemon函数:主要用于希望脱离控制台,以守护进程形式在后台运行的程序。
#include <stdio.h>
#include <unistd.h>
int main(){
daemon(0,0);
while(1);
}