目录
进程组
是一个或多个进程的集合
- 每个进程组除了有一个进程ID之外,还属于一个进程组。进程组是一个或多个进程的集合。
- 通常他们与同一个作业有关,可以接受来自同一端的各种信号。
- 每个进程组有唯一一个进程组ID,
- 进程组中有一个进程是组长进程,进程组的id就等于这个进程的pid
- 进程组并不会随着组长进程的退出而退出,而是组中所有的进程退 出后才会退出
查看命令:ps axj | head -1 && ps axj | grep test
PGID:组ID
ctrl+c:这种操作是针对前台进程组中的所有进程(退出进程组)
作业
- 是一个或多个进程的集合
- 一个终端前后台的控制不是仅进程组还有作业
- 一个终端有前台作业也有后台作业,但是前台作业只有一个
一般情况下shell是终端的前台作业,当运行了一个命令,那么这个命令将成为前台作业,bash将作为后台作业(因此这时输入的命令将不被执行),当命令运行完毕,bash又成为前台作业
- 作业就是干活的,一个终端下有两类干活的
- 一类是前台干活的,一类是后台干活的
- 因此作业的分类有前台作业和后台作业
- 一个终端中,前后台控制的通过作业和进程组完成的
- 一个终端中,前台作业只有一个,后台作业可有多个
作业有关的信号
- jobs可以查看后台进程
- fg+代号 可以将后台作业提到前台
- bg让某个停止的作业在后台继续运行
- 向停止状态的进程发信号时不作处理(因为处在T状态),直到提到前台后才会处理信号
- kill -9 强制杀死,如果杀不死(信号忽略,僵尸进程,停止状态)
进程组与作业的区别:
前台进程的子进程是不属于当前作业的,但是他们属于同一个进程组会话
会话
- 会话是一个或多个进程组的集合,实际上可有说成是一个会话周期
- 对于登录,登陆成功则开始一个会话,可能会有一个终端、
- 其中这个会话中有一个会话首进程,这是进程是shell(bash),这个进程将会话与终端联系起来
- 一个会话中会有一个前台进程组和任意多个后台进程组
- (所以一个会话中应该包括控制进程(会话首进程),一个前台进程组和任意多个后台进程组)
- 登录成功之后我们所运行的进程都属于会话
作业控制
shell分前后台控制的不是进程而是作业或者进程组,一个前台作业可以有多个进程组成,
一个后台作业也可以有多个进程组成,shell可以同时运行一个前台作业和任意多个后台作业
这就称为作业控制
守护进程(精灵进程)
守护进程,也就是通常说的Daemon进程,特殊的孤儿进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件
守护进程特点:
1:后台运行
2:脱离于终端联系,脱离会话,不受原终端和会话影响
3:Linux 的大多数服务器就是用守护进程实现的。比如,Internet 服务器 inetd,Web 服务器 httpd
守护进程脱离终端的主要原因有两点:
(1)用来启动守护进程的终端在启动守护进程之后,需要执行其他任务。
(2)(避免进程被任何终端所产生的信息所打断)其在执行过程中的信息也不在任何终端上显示。由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭
创建孤儿进程
孤儿进程——》建立一个新的会话——》关闭描述符——》重新设置当前工作路径-——》设置文件默认创建权限掩码——》成功逆袭成为守护进程
1:
#include <unistd.h>
int daemon(int nochdir, int noclose);
nochdir:如果是0将会改成根目录
noclose:如果是0重定向到 /dev/null
2:
孤儿进程——》建立一个新的会话——》关闭描述符——》重新设置当前工作路径-——》设置文件默认创建权限掩码——》成功逆袭成为守护进程
1:后台运行
2:脱离与终端关系,脱离原会话,不受原会话和终端的影响
有时会退出两次,第二次退出不是必要的,只是为了防止重新与终端联系起来
退出是为了守护进程不是会话首进程
TTY:终端号
可以使用tty查看
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
//实现守护进程
void daemon_t()
{
int pid = -1;
pid = fork();
if(pid < 0)
exit(-1);
else if(pid > 0)
exit(0);
//这时候就成为一个孤儿进程
//需要脱离原会话,因此需要新建会话
if(setsid() < 0)
exit(-1);
pid = fork();//子进程的子进程
if(pid < 0) //非必要,防止重新与终端联系起来
exit(-1);
else if(pid > 0)
exit(0);
//这时候就成为一个孤儿进程
//需要脱离原会话,因此需要新建会话
if(setsid() < 0)
exit(-1);
//这时已经可以称为守护进程了
umask(0);//权限掩码
chdir("/");
//关闭与终端联系
int fd = open("/dev/null",O_RDWR);
if(fd < 0)
{
exit(1);
}
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
// close(0);简单方式
// close(1);
// close(2);
}
int main()
{
daemon_t();
while(1)
{}
return 0;
}