目录

  • 什么是守护进程?
  • 守护进程、前台进程、后台进程的区别?
  • 前台进程和后台进程
  • 后台进程和守护进程
  • C语言实现守护进程


什么是守护进程?

守护进程是一个在后台运行并且不受任何终端控制的进程。

很多进程名字后面加了个d,基本就是个守护进程(这算个约定俗称的规则)。比如:

centos7 mysql 设置守护进程 mysql守护进程是什么_#include


mysql(数据库),ssh(shell登录),cron(定时器)都是以守护进程的方式在运行。

守护进程、前台进程、后台进程的区别?

前台进程和后台进程

先聊下前台进程和后台进程的差别。这里写个简单的测试例子。

// gcc -g -O0 test.c -o test

#include <sys/wait.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    int i = 0;
    while(1)
    {
        printf("into while %d\n", i++);
        sleep(10);
    }
}

centos7 mysql 设置守护进程 mysql守护进程是什么_#include_02


如上图,如果直接启动./test,那么它是个 前台进程,或者称为前台任务(foreground job),它会独占命令行窗口,只有运行完了或者手动中止,才能执行其他命令。

如果是./test &方式启动(后面加一个&符号),那么它就变成后台进程,也可以称为后台任务(background job)。

后台任务会:
1. 继承当前 session(对话)的标准输出(stdout)和标准错误(stderr)。因此,后台任务的所有输出依然会同步地在命令行下显示。
2. 不再继承当前 session 的标准输入(stdin)。你无法向这个任务输入指令了。如果它试图读取标准输入,就会暂停执行(halt)。

也可以用bg命令使任务变成后台任务,fg命令使任务再变回前台任务。如下:

centos7 mysql 设置守护进程 mysql守护进程是什么_#include_03

后台进程和守护进程

Q:后台进程是否就是守护进程了呢?或者说,用户退出session(也即:用户退出shell)后,后台进程是否还会继续执行?
A:后台进程和守护进程不一样。

这里涉及到SIGHUP信号。我们先了解下,退出shell的过程
step1:用户准备退出session(shell)。
step2:系统向该shell窗口进程发出SIGHUP信号。
step3:shell窗口进程将SIGHUP信号发送给所有子进程。
step4:子进程受到SIGHUP信号,自动退出。

这里其实间接解释了为何前台进程会随着shell退出而退出。

  • 对于前台进程,当shell退出,子进程会收到SIGHUP信号而退出;
  • 对于后台进程,当shell退出,是否发送SIGHUP信号给后台进程,取决于shell的 huponexit 参数,当该参数是off,则shell退出,不会发送SIGHUP信号给后台进程;当该参数是on,则shell退出时,会发送SIGHUP信号给后台进程,则后台进程也会跟随退出。

想要看huponexit参数的值,可以使用 shopt 命令。

shopt | grep huponexit

我测试机的结果是:

centos7 mysql 设置守护进程 mysql守护进程是什么_后台进程_04


因此,后台进程和守护进程并不相同,比如:有的系统huponexit是on的话,那么shell退出时候,后台进程也会相应地退出。

那么如何使得后台进程变成守护进程呢?
可以使用nohup命令。也可以用disown命令,不过稍微繁琐一点,这里不展开讲,有兴趣参考链接。下面讲解 nohup 命令。

举例,写一个循环例子:

// gcc -g -O0 test.c -o test

#include <stdio.h>

int main(int argc, char *argv[])
{
    int i = 0;
    while(1)
    {
        printf("i=%d\n", i++);
        
        // 这个语句很重要,没有这句fflush,nohup.out可能没有输出
        fflush(NULL);
        sleep(1);
    }
}

运行命令:

nohup ./test &

centos7 mysql 设置守护进程 mysql守护进程是什么_后台进程_05


centos7 mysql 设置守护进程 mysql守护进程是什么_#include_06


如果不想用默认的输出nohup.out,可以自己指定输出:

nohup ./test > a.txt 2>&1 &

centos7 mysql 设置守护进程 mysql守护进程是什么_#include_07

centos7 mysql 设置守护进程 mysql守护进程是什么_#include_08

总结
nohup都干了些什么事?
nohup命令实际将shell的子进程和shell进程本身分离,主要做了下面三件事:

  • 阻止SIGHUP信号发到这个进程。
  • 关闭标准输入。该进程不再能够接收任何输入,即使运行在前台。
  • 重定向标准输出和标准错误到文件nohup.out。(这个可以自定义修改)

注意

  • nohup命令不会自动把进程变为"后台任务",所以必须加上&符号。

C语言实现守护进程

简单 一点,直接用daemon函数即可,当然,复杂点,还可以自己实现守护进程的逻辑,比如:让程序在后台执行、调用setsid()创建一个新对话期、禁止进程重新打开控制终端、关闭不再需要的文件描述符、将当前目录更改为根目录、子进程从父进程继承的文件创建屏蔽字可能会拒绝某些许可权、处理SIGCHLD信号 等等。这个就不展开讲,有兴趣自己百度下,我们这边还是讲最简单的系统API daemon函数

头文件
#include <unistd.h>
函数原型
int daemon(int nochdir, int noclose);
参数
nochdir=0,daemon函数会把当前工作目录改为根目录;否则,当前工作目录保持不变。
noclose=0,daemon函数重定向标准输入、标准输出、标准错误到/dev/null;否则,不会重定向这三个fd(即:0,1,2)。
返回值
成功返回0;失败返回-1,并会设置errno。

举例:

// gcc -g -O0 test.c -o test

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    daemon(1, 0);
    
    int i = 0;
    while(1)
    {
        printf("i=%d\n", i++);
        
        // 这个语句很重要,没有这句fflush,nohup.out可能没有输出
        fflush(NULL);
        sleep(1);
    }
}

centos7 mysql 设置守护进程 mysql守护进程是什么_#include_09