文章目录
- 一、前台进程和后台进程
- 二、Linux 的进程间关系
- 三、setsid——将当前进程设置为守护进程
- 四、daemon——设置为守护进程
- 五、结语
一、前台进程和后台进程
Linux
中每一次用户登录都是一个 session
,一个 session
中只能有一个前台进程在运行,键盘信号只能发送给前台进程,其中谁拥有键盘文件谁就是前台进程。./process &
表示启动一个后台进程,后台进程和前台进程可以同时向显示器进行打印。
jobs
查看后台进程。
fg 后台任务号
将一个后台进程提到前台。如果 ctrl+z
将一个前台进程给暂停了,那么操作系统会把 bash
提到前台来,并且把暂停的进程放到后台。在命令行中前台进程一定要存在。bg 后台任务号
将一个因为暂停而被放到后台的任务重新启动,启动后是在后台运行。
二、Linux 的进程间关系
其中 PGID
是进程组 ID,一个任务会对应一个进程组,一个任务可能需要几个进程共同来完成。多个任务(进程组),在同一个 session
内启动的,sid
是一样的,该 sid
其实就是操作系统为该会话所创建的 bash
的 pid
我们在 Xshell 上关闭连接(退出登录)后,操作系统并没有把之前登录创建的 session
全部清理掉,没有把该 session
下的后台进程全部终止掉,但是在其他一些操作系统上,例如 Windows
,它的注销功能,就是把当前 session
中的全部进程全部终止。为了避免出现用户退出后,进程被终止,这里引出守护进程的概念,所谓守护进程,就是该进程自成进程组,自成会话。
三、setsid——将当前进程设置为守护进程
#include <unistd.h>
pid_t setsid(void);
- 返回值:成功,返回一个新的
sid
,一般都是当前进程的pid
。失败,-1被返回,错误码被设置。 - 注意:调用该函数的进程不能是某个进程组的组长。而我们一般直接在命令行
./
执行的某个可执行文件,都是自成进程组的,自己就是进程组的组长,所以要向实现守护进程,非常重要的一步就是fork
创建子进程,然后让父进程退出,此时子进程的组 ID 就是父进程的 PID,而不是自己的 PID,此时就可以在子进程中调用setsid
函数。守护进程的本质也是孤儿进程,它会被操作系统领养,但是它为自己创建了一个新的会话(session
),此时就不受任何用户登录和注销的影响。
守护进程的过程分为以下四步:
-
忽略其他异常信号
-
创建子进程,终止父进程,让子进程成为一个独立的会话
-
更改当前的工作目录
-
将标准输入、标准输出、标准错误重定向到
/dev/null
(相当于一个垃圾箱,输入进程的东西都被丢弃了,并且从里面获取不到任何输入)
// Daemon.hpp
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
const std::string nullfile = "/dev/null";
void Daemon(const std::string &cwd = "")
{
// 1. 忽略其他异常信号
signal(SIGCHLD, SIG_IGN); // 17号信号——子进程退出给父进程发送这个信号
signal(SIGPIPE, SIG_IGN); // 读端关闭写端正常,操作系统会给写端发送13号信号,终止掉写端
signal(SIGSTOP, SIG_IGN); // 暂停信号
// 2. 创建子进程,将父进程终止,让子进程变成独立的会话
if (fork() > 0)
exit(0);
setsid();
// 3. 更改当前的工作目录
if (!cwd.empty())
chdir(cwd.c_str());
// 4. 将标准输入,标准输出,标准错误重定向至 /dev/null(这就相当于一个垃圾箱,输入进去的内容都会被丢弃)
int fd = open(nullfile.c_str(), O_RDWR);
if(fd > 0)
{
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
}
小Tips:一般守护进程的名字都以 d
结尾。
四、daemon——设置为守护进程
daemon
函数是系统为我们提供的将一个进程设置成守护进程的函数。
#include <unistd.h>
int daemon(int nochdir, int noclose);
nochdir
为 0 表示将进程的工作目录设置到 /
目录。noclose
表示将标准输入、标准输出、标准错误重定向到 /dev/null
中。
五、结语
今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,春人的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是春人前进的动力!