一、历程组
1、理解
每一个历程除了有一个历程 ID(PID)之外 还属于一个历程组, 历程组是一个大概多个历程的集合, 一个历程组可以包含多个历程。 每一个历程组也有一个唯一的历程组 ID(PGID), 并且这个 PGID 雷同于历程 ID, 同样是一个正整数, 可以存放在 pid_t 数据范例中。 2、举例
上图就是用管道创建了一个历程组。
我们可以用 ps ajx | head -1 && ps ajx | grep sleep,来查看指定的历程。 发现PGID是一样的2114632。 3、结论
PGID是历程组组长的PID,历程组组长可以创建一个历程组,也可以在自己的历程组里面创建新历程(父历程) 历程组的声明周期终止于末了一个历程退出,与组长无关。 二、会话
1、理解
会话可以看成是一个或多个历程组的集合, 一个会话可以包含多个历程组。每一个会话也有一个会话 ID(SID)
如三个历程SID雷同,阐明构成的历程组在同一个会话中。 2、Linux会话结构
首先我们登录Linux之后,先有 bash 历程创建终端文件,此时 bash 不但是历程组组长,bash 历程组还是会话组长,我们大部门的工作都是在 bash 创建的会话里面完成的。创建与控制终端连接的会话首历程是控制历程 bash。
3、结论
(1)在同一个会话中允许存在多个历程组。
(2)但是前台历程只有一个,背景历程可以有多个
例如我在前台启动一个历程组,输入指令 bash 由于在背景,就不会处理指令。
(3)前背景:前台可以从标准输入中获取数据。历程在启动时末了带上&就是背景历程
(4)无论何时,发送的制止信号只能给前台历程。
三、控制终端
在 UNIX 系统中, 用户通过终端登录系统后得到一个 Shell 历程,这个终端成为 Shell 历程的控制终端。控制终端是保存在 PCB 中的信息,我们知道 fork 历程会复制 PCB 中的信息,因此由 Shell 历程启动的别的历程的控制终端也是这个终端。 默认环境下 没有重定向,每个历程的标准输入、标准输出和标准错误都指向控制终端,历程从标准输入读也就是读用户的键盘输入,历程往标准输出或标准错误输出写也就是输出到显示器上。别的会话、历程组以及控制终端另有一些其他的关系: 一个会话可以有一个控制终端,通常会话首历程打开一个终端(终端装备或伪终端装备)后,该终端就成为该会话的控制终端。 创建与控制终端连接的会话首历程被称为控制历程 。 一个会话中的几个历程组可被分成一个前台历程组 以及一个大概多个 背景进 程组 。 假如一个会话有一个控制终端,则它有一个前台历程组,会话中的其他历程组则为背景历程组。 无论何时进入终端的制止键(ctrl+c )或退出键( ctrl+\ ),就会将制止信号发送给前台历程组的所有历程。 假如终端接口检测到调制解调器(或网络)已经断开,则将挂断信号发送给控制历程(会话首历程)。 四、作业与作业控制
1、理解
作业 是针对用户来讲,用户完成某项使命而启动的历程,一个作业既可以只包含一个历程,也可以包含多个历程,历程之间相互协作完成使命, 通常是一个历程管道。 2、作业控制操作
jobs:查看作业。-p查看作业pid
关于默认作业:对于一个用户来说,只能有一个默认作业(+),同时也只能有一个即将成为默认作业的作业(-),当默认作业退出后,该作业会成为默认作业。 + : 表示该作业号是默认作业 -:表示该作业即将成为默认作业 无符号: 表示其他作业 fg 作业号:把一个指定作业提到前台(担当用户输入的数据)
把作业放回背景:(1)作业停息(ctrl z,也叫挂起)之后OS就会把作业放回背景。(2)bg 作业号:在背景启动作业
3、作业状态
4、举例
五、守护历程
1、理解
一个服务历程独立成为一个会话,就不会受原来会话的影响。
2、把历程变成守护历程
不是历程组组长调用函数 setsid 就可以把自己变成守护历程。调用的历程就会变成新会话的首历程,此时会话中只有一个历程,也是一个历程组的组长。
做法:父历程先 fork 子历程,父历程退出,子历程调用函数,由于子历程继承父历程的历程组id,历程id被重新分配,所以守护历程是孤儿历程。
这种历程已经不属于 bash 会话,只能用 kill 杀死历程。
3、代码实现
- #pragma once
- #include <iostream>
- #include <cstdlib>
- #include <signal.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- const char *root = "/";
- // 路径/dev/null 文件里面的数据不能被读取,相当于是被丢弃
- const char *dev_null = "/dev/null";
- void Daemon(bool ischdir, bool isclose)
- {
- // 1. 忽略可能引起程序异常退出的信号
- signal(SIGCHLD, SIG_IGN);
- signal(SIGPIPE, SIG_IGN);
- // 2. 让自己不要成为组长,父进程退出
- if (fork() > 0)
- exit(0);
- // 3. 设置让自己成为一个新的会话, 后面的代码其实是子进程在走
- setsid();
- // 4. 每一个进程都有自己的 CWD,是否将当前进程的 CWD 更改成为 / 根目录
- if (ischdir)
- chdir(root);
- // 5. 已经变成守护进程,不需要和用户的输入输出,错误进行关联了
- if (isclose)
- {
- close(0);
- close(1);
- close(2);
- }
- else
- {
- // 这里一般建议就用这种
- int fd = open(dev_null, O_RDWR);
- if (fd > 0)
- {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- close(fd);
- }
- }
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |