Linux:守护进程

本文深入探讨了守护进程(Daemon)的概念及其在Linux系统中的作用。解释了守护进程如何独立于控制终端运行并周期性执行特定任务。通过具体示例介绍了守护进程的创建过程,包括使用setsid函数成为话首进程的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们上篇博客在会话中,提到了话首进程bash。我们再来看看这个话首进程。
这里写图片描述
我们在查看bash进程的时候,发现在PPID这一栏,话首进程也是有父进程的。它的父进程的ID是27357,这就奇怪了,按道理来说打开终端,bash最先运行。难道打开终端前还有比bash更先的进程已经运行了?我们再来看看这个27357到底是什么?
这里写图片描述
我们发现在bash前还是有别的进程的。而这些进程是什么时候运行的呢?如果这些进程时在打开终端时运行,那么为什么它们不是话首进程呢?

这时候就要引入一个新的概念:守护进程!!!

守护进程(Daemon)

守护进程也叫作精灵进程,是在后台运行的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或者处理某些发生的事件。Linux的大多是服务器就是用守护进程实现的。Linux系统启动的时候会启动很多系统服务进程,这些系统服务进程没有控制终端,不能与用户之间交互。其它进程都是在用户登录或运行程序的时候创建的,在运行结束或者用户注销的时候终止。但是系统服务进程(守护进程)不受用户登录注销的影响,它们一直在运行。

我们可以用指令ps axj来查看进系统中的进程。其中参数a表示不仅列当前用户的进程,也列出所有其他用户的进程。参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数j表示列出与作业控制相关的进程。
这里写图片描述

  • 凡是TGID一栏写着-1的都是没有控制终端的进程,也就是守护进程。
  • 在COMMAND一列用[ ]括起来的名字表示内核线程,这些线程在内核里创建,没有空间代码,因此没有程序文件名和命令行,通常采用以k开头的名字,表示Kernel内核。
  • 可以看出,守护进程通常采用以d结尾的名字,表示Daemon。

守护进程的创建

#include <unistd.h>

pid_t setsid(void);
//创建守护进程,该函数调用成功返回新创建的会话的ID
//也就是调用该函数的进程ID,调用失败返回-1

创建守护进程最关键的一步就是调用setsid函数后创建一个新的会话,并成为会话的话首进程。但是调用这个函数之前,这个进程不允许是该进程组的组长,否则调用失败。因为不允许两个进程组的组ID是同一个ID,所以不允许进程组的组长调用这个函数。
要解决这个问题,其实也很简单。我们可以在进程中利用fork创建子进程,然后让子进程调用setsid,这时候子进程一定不是该进程组的组长,所以一定调用成功。

成功调用该函数的结果是:

  • 创建一个新的会话,并且当前进程称为话首进程,当前进程ID就是会话ID
  • 创建一个新的进程组,当前进程称为该进程组的组长,当前进程ID就是进程组ID
  • 如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是一个普通文件,而不是控制终端。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>

void mydeamon()
{
  int fd0;
  pid_t id;
  struct sigaction sa;

  //设置屏蔽字为0
  umask(0);

  id = fork();
  if(id < 0)
  {
    printf("fork error!\n");
    exit(1);
  }
  //让父进程退出
  if(id > 0)
  {
    exit(0);
  }

  if(setsid() < 0)
  {
    printf("setsid error!\n");
    exit(1);
  }
  //初始信号集
  sigemptyset(&sa.sa_mask);
  sa.sa_handler = SIG_IGN;
  sa.sa_flags = 0;

  //忽略SIGCHLD信号
  if(sigaction(SIGCHLD, &sa, NULL) < 0)
  {
    perror("sigaction");
    exit(1);
  }

  fd0 = open("/dev/null", O_RDWR);
  close(0);
  dup2(fd0, 1);
  dup2(fd0, 2);
}

int main()
{
  mydeamon();

  while(1) {
    sleep(1);
  }

  return 0;
}

这里写图片描述
创建之后,我们注销掉这个终端,再次重启之后,发现此时守护进程还在。
这里写图片描述


欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值