Linux---守护进程

运行的这个进程,它的pid和gpid(进程组ID)一样,它是自成一组的。

这就是一个进程组。

进程组和任务有什么关系?

将任务指派给进程组。任务都是由进程组去完成的。

可以发现,这三个进程的会话id1351都是一样的,多个任务(进程组),在同一个sesion内启动的sid是一样的。


当后台任务在执行的时候,我将用户退出,后台任务就会受到退出的影响。

如果不想受到用户登录和注销的影响---守护进程话

当前用户在登录的时候,让其中的某个进程组自成一个会话,这个会话不需要和键盘显示器什么的关联。这种自称进程组会话的进程,叫守护进程。

此时再把用户退出,这个进程不会受到任何影响。

Linux---守护进程_第1张图片


setsid 是一个Linux系统调用,用于创建一个新的会话(session)。
这个新的会话通常是用于创建守护进程(daemon)的。
#include 

pid_t setsid(void);
(进程组的组长不能独立成一个会话)

第1步:fork子进程,父进程退出子进程继承了父进程的进程组id,但具有一个新的进程id,这样就保证了子进程不是一个进程组的组长id,这对于下面要做的setsid函数的调用是必要的前提条件

第2步:子进程调用 setsid函数创建新会话调用这个函数以后该进程成为新会话的首进程,是会话的会长成为一个新进程组的组长进程,是进程组组长不受控制终端的影响

第3步:改变当前工作目录chdir如:a.0ut在u盘上,启动这个程序,这个程序的当前的工作目录就是这个u盘,如果u盘拔掉后进程的当前工作目录将消失,a.out将不能正常工作。

第4步:重设文件掩码 mode & umask子进程会继承父进程的抢码 中,增加子进程程序操作的灵活性umask(0000);

第5步:关闭文件描述符守护进程术受控制终端的影响所以可以关闭,以释放资源

close(stdin_fileno);

close(stdout_fileno);

close(stderr_fileno);

第6步:执行核心工作守护进程的核心代码逻辑

345部不是必须的

守护进程一般以d结尾命名

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void myfunc(int signo)
{
    int fd = open("./session.txt", O_RDWR | O_CREAT | O_APPEND, 0755);
    if (fd < 0)
    {
        return;
    }
    // 打开文件成功后获取当前时间
    time_t t;
    time(&t);

    char *p = ctime(&t);

    write(fd, p, strlen(p));

    close(fd);
    return;
}

int main()
{
    // 1.创建子进程
    pid_t id = fork();
    if (id != 0)
        exit(0);

    // 2.子进程调用setsid函数创建会话
    setsid();

    // 3.改变工作目录(可选)
    // chdir();

    // 4.文件掩码(可选)
    // umask(0000);

    // 5.关闭标准输入,标准输出,标准错误文件描述符
    // close(STDIN_FILENO);
    // close(STDOUT_FILENO);
    // close(STDERR_FILENO);
    // 也可以将这三个文件重定向到黑洞文件 /dev/null 中。这个文件通常用于丢弃数据
    int fd = open("/dev/null", O_CREAT | O_RDWR | O_APPEND, 0775);
    if (fd < 0)
    {
        exit(-1);
    }
    dup2(fd, 0);
    dup2(fd, 1);
    dup2(fd, 2);
    close(fd);

    struct sigaction act;
    act.sa_flags = 0;
    act.sa_handler = myfunc;
    sigemptyset(&act.sa_mask);
    sigaction(SIGALRM, &act, nullptr);

    struct itimerval tm;
    tm.it_interval.tv_sec = 2;
    tm.it_interval.tv_usec = 0;
    tm.it_value.tv_sec = 3;
    tm.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &tm, NULL);

    while (1)
    {
        sleep(1);
    }

    return 0;
}

程序运行之后,直接去后台了。PPID为1,PID PGID SID都一样,自成进程组,自成会话。

Linux---守护进程_第2张图片

下面我将云服务器关了。一会登录查看日志文件。

Linux---守护进程_第3张图片

用户的退出或者登录该任务没有任何影响。


Linux提供了守护进程的系统调用接口

daemon 函数用于将当前进程转变为守护进程(daemon)。
#include 
int daemon(int nochdir, int noclose);
nochdir:如果 nochdir 不为0,表示不改变当前工作目录为根目录(/);
         如果为0,则会将当前工作目录更改为根目录。
noclose:如果 noclose 不为0,表示不关闭标准输入、标准输出和标准错误文件描述符;
         如果为0,则会关闭这些文件描述符。
daemon 函数的返回值为0表示成功,-1表示失败。

你可能感兴趣的:(Linux,Linux)