赞
踩
作者:爱写代码的刚子
时间:2024.4.27
前言:本篇博客将会介绍守护进程,以及进程组和会话的概念,如何变成守护进程等知识
守护进程也叫做精灵进程,是运行在后台的一种特殊进程他独立于控制终端并且可以周期性的执行某种任务或者等待处理某些发生的事件。守护进程是非常有用的进程,在Linux当中大多数服务器用的就是守护进程比如Web服务器httpd等,同时守护进程完成很多系统的任务。当Linux系统启动的时候,会启动很多系统服务,这些进程服务是没有终端的也就是说你把终端关闭了这些系统服务是不会停止的,他们一直运行着他们有一个名字就叫做守护进程。一般以服务器的方式工作,对外提供服务的服务器,都是以守护进程(精灵进程)的方式在服务器中工作的,一旦启动之后,除非用户主动关闭,否则,一直会在运行。
进程组的相关概念:
进程除了有进程的PID之外还有一个进程组,进程组是由一个进程或者多个进程组成。通常他们与同一作业相关联可以收到同一终端的信号
每个进程组有唯一的进程组ID,每个进程组有一个进程组组长。如何判断一个进程是不是这个进程组的组长了,通常进程组ID等于进程ID那么这个进程就是对应进程组的组长。
会话的相关概念:
无论是前台进程还是后台进程,都可以向显示器打印,一个session只能有一个前台进程运行,键盘信号只能发给前台进程(谁拥有键盘文件,谁就是前台进程)
jobs查看后台进程
fg +任务号将后台任务提到前台
ctrl + z将前台进程暂停并放到后台
bg +任务号将暂停的后台进程重新启动
进程与进程之间不仅有进程独立性的关系,还有进程组的关系
bash是独立成进程组独立成会话的一个进程
我们新打开了一个会话,发现bash进程变多了
从上面我们可以看到纯后台进程是会收到用户登陆和退出的影响的
不想受到任何用户登陆和注销的影响就要——守护进程化
我们将自成进程组、自成会话的进程叫做守护进程,与bash变成并列关系而不是包含关系
注意,要调用这个函数,调用的进程不能是进程组的组长
【问题】:如何保证自己不是组长?
调用fork()函数,让父进程退出,子进程调用setsid()
if(fork() > 0) exit(0);setsid()
所以守护进程的本质也是孤儿进程
Daemon.hpp
#pragma once #include <iostream> #include <cstdlib> #include <unistd.h> #include <signal.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(SIGCLD,SIG_IGN);//父进程不需要调用wait进行回收子进程 signal(SIGPIPE,SIG_IGN); signal(SIGSTOP,SIG_IGN); //2. 将自己变成独立的会话 if(fork() >0) exit(0); setsid(); //3. 更改调用进程的工作目录 if(!cwd.empty()) { chdir(cwd.c_str()); } //Daemon函数可以运用到服务器Start()函数的开头,将该进程变成守护进程,但是我们可能会想到,服务器中会存在大量的打印,往标准输出打 //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); } }
第一行 -D 结尾的就是服务器(守护进程)。它的PPID是1。下面来介绍上述选项的意义:
COMMAND:启动的进程命令名称
TIME:进程启动的时长
UID:是谁启动的
STAT:状态
TPGID:当前进程组和终端的关系(如果是-1,则没有任何关系)
TTY:代表哪一个终端
SID:当前进程的会话ID
PGID:当前进程所属的进程组
PID:当前进程自己的ID
PPID:当前进程的父进程的ID
所以守护进程一般以d结尾,一般把日志信息存放到文件中
于是便有了日志信息
/dev/null
,否则不做处理。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。