【Linux】进程间关系和守护进程

目录

1. 终端

2. 进程组

3. 作业

4. 会话

5. 守护进程

5.1 创建守护进程


1. 终端

终端是所有输入/输出设备的总称,如 字符终端、伪终端、图形终端、网络终端等。

UNIX 系统中,用户通过终端登录系统后得到一个 Shell 进程,这个终端称为 Shell 进程的控制终端。

简单来说,一个 Linux 系统启动,大概需要经历以下步骤:

init -> fork -> exec -> getty -> login -> passwd -> exec -> bash

line disciline:线路规程,处理键盘输入信息,若为字符,则显示,若不为字符(如键盘输入 ctrl+z),则对应的字符并不会被用户程序中的 read 读到,而是被线路规程截获,解释为 SIGSTOP 信号发给前台进程,通常会使该进程停止。

char *ttyname(int fd); 
// 根据文件描述符查找出对应的终端名
// 成功:终端名;
// 失败:NULL,并设置 errno

tty1 是文字终端,只能通过命令行来控制。而 /pts/1 是虚拟终端,可以使用图形界面。

crw-rw-rw- 1 root root 1, 5 10月 1 11:25 /dev/zero
# 这里的 1 是 伪终端主设备号, 5 是伪终端从设备号。

2. 进程组

进程组,也称之为作业,代表一个或多个进程的集合。

当父进程创建子进程时,默认子进程与父进程属于同一进程组。此时 进程组 id 等于 第一个进程 id(组长进程)。
所以,组长进程的标识为:pgid == pid

可以使用 kill -SIGKILL -pgid(负的) 或者 kill -9 -pgid 来将整个进程组内的进程全部杀死。

只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关

进程组生存期:从进程组创建开始到最后一个进程离开(终止或转移到另一个进程组)

// 获取当前进程的进程组ID
    pid_t getpgrp(void); // 返回调用者的 pgid
// 获取指定进程的进程组ID
    pid_t getpgid(pid_t pid); // 成功:0;失败:-1,并设置 errno /* 如果pid = 0,那么该函数作用和 getpgrp 一样。即就是获取 pgid */
// 改变进程默认所属的进程组。通常可用来加入一个现有的进程组或创建一个新进程组。
    int setpgid(pid_t pid, pid_t pgid); // 成功:0;失败:-1,并设置 errno
/* 将 参数 1 对应的进程,加入参数 2 对应的进程组中。
注意:
	1. 如改变子进程为新的组,应在 fork 后,exec 前。
	2. 权限问题。非 root 进程只能改变自己创建的子进程,或有权限操作的进程。*/
前台进程 ---> 后台进程
    ctrl+z   
后台进程 ---> 前台进程
    fg [job号]  
查看后台进程状态
    jobs
ps选项
    a: 不仅列出当前用户的进程,也列出所有其他用户的进程。
    x: 表示不仅列出有控制终端的进程,也列出所有无控制终端的进程。
    j: 表示列出与作业控制相关的信息。

3. 作业

shell 分前后台来控制的不是进程,而是作业(job)或者进程组。

shell 可以运行一个前台作业和任意多个后台作业,这称为作业控制。

作业和进程组的区别:

  • 如果作业中的某个进程又创建了子进程,则该子进程不属于作业。
  • 一旦作业运行结束,shell 就把自己提到前台(子进程还在,可是子进程不属于作业),如果原来的前台进程还存在(如果这个子进程还没终止),它自动变为后台进程组。
  • 在前台新起作业,shell 是无法运行的,因为他被提到了后台。 但是如果前台进程退出,shell就又被提到了前台,所以可以继续接受用户输入。

4. 会话

会话(session)是一个或多个进程组的集合。

创建一个会话需要注意以下 6 点:

  • 调用进程不能是进程组组长,该进程变成新会话首进程(session header)
  • 该进程成为一个新进程组的组长进程
  • 需有 root 权限(ubuntu 不需要)
  • 新会话丢弃原有的控制终端,该会话没有控制终端    即就是不能交互
  • 该调用进程是组长进程,则出错返回
  • 建立新会话时,先调用 fork,父进程终止,子进程调用 setsid

组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程。

// 获取进程所属的会话ID
pid_t getsid(pid_t pid); // 成功:返回调用进程的 sid;失败:-1,并设置errno
/* pid 为 0 表示查看当前进程session id */
// 设置 sid
pid_t setsid(void); // 成功:返回调用进程的 sid;失败:-1,并设置errno
/* session: pid = sid = pgid */

5. 守护进程

Linux 下的服务,我们称为守护进程(Daemon)或者精灵进程,是运行在后台的一种特殊进程。它通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件,不受用户登录、注销的影响,一直在运行着,并且一般以 d 结尾。Linux 的大多数服务器就是用守护进程实现的,比如 ftp、ssh 等等。

通过 ps axj 可以看到 Linux 下的一些守护进程,凡是 TPGID 一栏写着 -1 的都是没有控制终端的进程,也就是守护进程。

守护进程的特点:

  • 后台运行
  • 脱离终端会话

5.1 创建守护进程

1. fork()创建子进程,父进程退出
2. 在子进程中使用 setsid() 创建新会话,使子进程完全独立出来,脱离终端控制
3. 使用 chdir() 改变当前目录为根目录,也可以换成其它路径,这是为了防止占用可卸载的文件系统(如 卸载不到 u 盘)
4. 利用 umask() 重设文件权限掩码,防止文件掩码被改变
5. 关闭文件描述符,将 0 1 2 重定向到 /dev/null,这是因为 0 1 2 默认是打开的,浪费资源
如:
    close(0);
    int fd = ("/dev/null", O_WRONLY);
    dup2(fd, 1);
    dup2(fd, 2);
当然也可以 close() 0-254 这些文件描述符
for (int i = 0; i < 255; i++) { 
    close(i); 
}
6. 开始执行守护进程核心代码

除了上述方式创建守护进程外,还提供了 daemon()  来创建守护进程。

// 调用守护进程
#include <unistd.h>
int daemon(int nochdir, int noclose);
// 参数:
    1.如果 nochdir 为 0,那么会把当前路径改为根路径,如果非 0,那么不会修改。
    2.如果 noclose 为 0,那么会将 0 1 2 这些标准输入、输出、出错的文件重定向到 /dev/null 中,如果非 0,则不会关闭 0 1 2。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值