简述
不受用户登录、注销影响的进程称为守护进程
特点
后台运行:守护进程在后台默默地执行任务,不与用户交互。它不会向终端输出信息,也不会从终端接收输入。
无终端关联:守护进程通常与任何终端会话(比如SSH会话)无关联。即使用户注销或关闭终端,守护进程仍然继续运行。
独立性:守护进程通常是独立于其他进程的,它没有父进程。一般来说,守护进程是由操作系统启动的,并且不受其他进程的影响。
任务处理:守护进程通常用于执行一些系统级任务,例如定期备份、日志处理、网络服务等。它们可以在系统启动时自动启动,并在系统运行期间一直保持活动状态。
进程组
简述
进程组(Process Group)是一个或多个相关进程组成的集合。同一进程组中的进程共享同一个进程组ID(PGID),并且它们可以用于进行进程间通信和控制。
测试
sleep 1000 | sleep 2000 | sleep 3000 &
sleep 4000 | sleep 5000 | sleep 6000 &
我们使用以上命令来创建6个进程,最后的&符号是为了让他们在后台运行,而不占用当前的输入输出,当前的终端可以继续使用。
当我们使用ps对其查看的时候就可以看到对应的PGID(进程组ID)
当我们分别创建两组进程的时候,第一个创建的进程就被称为组长,并且这一组的进程组ID就是和该组长进程的PID是一致的。
fg与bg命令
作用
fg +作业号 将任务放到前台
bg+作业号 将任务放到后台
由于我们的Linux服务器有且只能有一个前台进程,所以使用fg让其他进程变成前台进程的时候,bash(命令行解释器)就自动被放到后台了。
作业
SID
在Linux中,SID(Session ID)是一个用于标识会话(Session)的唯一标识符。会话是包含一个或多个进程组的集合,其中一个进程是会话的领导者(Session Leader)。SID用于在内核中唯一标识每个会话。
守护进程的模拟实现
#pragma once
#include <unistd.h>
#include <signal.h>
#include <cstdlib>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define DEV "/dev/null"
void daemonSelf(const char *currPath = nullptr)
{
// 1. 让调用进程忽略掉异常的信号
signal(SIGPIPE, SIG_IGN);
// 2. 如何让自己不是组长,setsid
if (fork() > 0)
exit(0);
// 走到这里肯定是子进程 -- 守护进程,精灵进程,本质就是孤儿进程的一种!
pid_t n = setsid();
assert(n != -1);
// 3. 守护进程是脱离终端的,关闭或者重定向以前进程默认打开的文件
// 将文件描述符 0 1 2 对应的操作重定向到/dev/null里面
// 默认在/dev/null里面读和写 既不阻塞我们的读写操作,又不会读出和写出任何东西
int fd = open(DEV, O_RDWR);
if (fd >= 0)
{
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
else
{
close(0);
close(1);
close(2);
}
// 4. 可选:进程执行路径发生更改
if (!currPath)
chdir(currPath);
}
具体步骤:
1. 让调用进程忽略掉异常的信号
2. 让自己不是组长,setsid
3. 守护进程是脱离终端的,关闭或者重定向以前进程默认打开的文件
将文件描述符 0 1 2 对应的操作重定向到/dev/null里面
默认在/dev/null里面读和写 既不阻塞我们的读写操作,又不会读出和写出任何东西
4. 可选:进程执行路径发生更改