Linux 系统编程-守护进程
作者:
也许
,
2022-04-18 18:57:34
,
所有人可见
,
阅读 185
进程组和会话
进程组:
概念:
进程组,也称之为作业。代表一个或多个进程的集合。每个进程都属于一个进程组。在 waitpid 函数和 kill
函数的参数中都曾使用到。操作系统设计的进程组的概念,是为了简化对多个进程的管理。
特点:
1. 当父进程,创建子进程的时候,默认子进程与父进程属于同一进程组。进程组 ID==第一个进程 ID(组长进程)。
所以,组长进程标识:其进程组 ID==其进程 ID cat | cat | cat | cat | wc -l ----5个进程
2. 可以使用 kill -SIGKILL -进程组 ID (负的)来将整个进程组内的进程全部杀死。 kill -9 -进程组 ID
3. cat | cat | cat | cat | wc -l 假设第一个进程ID = 进程组ID = 5331
kill -9 5331 : 只杀死第一个进程,根据管道读写原则,读管道时,管道没有写端,返回0 其他进程正常结束
kill -9 -5331:整个进程组的进程全部杀死
会话:
概念:多个进程组组成一个会话, 比如bash是一个会话(session), 在bash下可以创建多个进程组
创建会话( 函数:setsid() )注意事项:
1. 调用此函数进程不能是进程组组长,否则出错返回
2. 调用此函数进程变成新会话首进程,调用进程成为一个新进程组的组长进程,
3. 新会话丢弃原有的控制终端,该会话没有控制终端
4. 组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程。
创建会话正确姿势:先调用 fork, 父进程终止,子进程调用 setsid()
总结:调用了 setsid 函数的进程,既是新的会长,也是新的组长。pid = gpid = spid
守护进程
概念:
daemon(精灵)进程。通常运行与操作系统后台,脱离控制终端。一般不与用户直接交互。周期性的等待某个事件发生或
周期性执行某一动作(服务器进程)。不受用户登录注销影响。通常采用以d结尾的命名方式。
守护进程创建步骤:
1. fork子进程,让父进程终止。
2. 子进程调用 setsid() 创建新会话 ======》目的是丢弃控制终端
3. 通常根据需要,改变工作目录位置 chdir(), 防止目录被卸载。
4. 通常根据需要,重设umask文件权限掩码,在守护进程中,影响新文件的创建权限。
5. 通常根据需要,关闭/重定向 文件描述符 fd = 0, 1, 2不会用到,要关闭。防止浪费系统资源
但是关闭0,1,2后,在守护进程中创建新文件后,新文件的文件描述符为0,不符合编程习惯,一般将0,1,2重定向
到 /dev/null (文件空洞),这样新创建的文件描述符就是3
6. 守护进程 业务逻辑。while()
创建守护进程:
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
pid_t pid;
int ret, fd;
pid = fork();
if (pid > 0) // 父进程终止
exit(0);
pid = setsid(); //创建新会话
if (pid == -1)
sys_err("setsid error");
ret = chdir("/home/itcast/28_Linux"); // 改变工作目录位置
if (ret == -1)
sys_err("chdir error");
umask(0022); // 改变文件访问权限掩码
close(STDIN_FILENO); // 关闭文件描述符 0
fd = open("/dev/null", O_RDWR); // fd --> 0
if (fd == -1)
sys_err("open error");
dup2(fd, STDOUT_FILENO); // 重定向 stdout和stderr
dup2(fd, STDERR_FILENO);
while (1); // 模拟 守护进程业务.
return 0;
}