十三、Linux系统编程-进程(六)进程组、会话期、守护进程

一、进程组、会话期、守护进程
进程组和会话之间的关系

(1)、进程组:一个或多个进程的集合
函数原型
pid_t getpgid(pid_t pid);
pid_t getpgrp(void);   
函数参数pid:进程id
返回值:调用进程的进程组id
getpgid(0)==getpgrp()
示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    pid_t pid;

    if ((pid=fork())<0) {
        printf("fork error!");
    }else if (pid == 0) {
        printf("The child process PID is %d.\n",getpid());
        printf("The Group ID is %d.\n",getpgrp());
        printf("The Group ID is %d.\n",getpgid(0));
        printf("The Group ID is %d.\n",getpgid(getpid()));
        exit(0);
    }

    sleep(3);
    printf("The parent process PID is %d.\n",getpid());
    printf("The Group ID is %d.\n",getpgrp());

    return 0;
}
(2)、组长进程:进程ID==进程组ID的进程
组长进程可以创建一个进程组,创建该进程组中的进程;只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关;进程组的生存期直到进程组最后一个进程退出。
函数声明:
int setpgid(pid_t pid, pid_t pgid);
函数参数:进程ID,进程组ID
返回值:成功返回0,失败返回-1
函数功能:改变进程pid的进程组ID为pgid

示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    pid_t pid;
    if ((pid=fork())<0) {
        printf("fork error!");
        exit(1);
    }else if (pid==0) {
        printf("The child process PID is %d.\n",getpid());
        printf("The Group ID of child is %d.\n",getpgid(0)); // 返回组id
        sleep(5);
        printf("The Group ID of child is changed to %d.\n",getpgid(0));
        exit(0);
    }

    sleep(1);
    setpgid(pid,pid); // 改变子进程的组id为子进程本身
    
    sleep(5);
    printf("The parent process PID is %d.\n",getpid());
    printf("The parent of parent process PID is %d.\n",getppid());
    printf("The Group ID of parent is %d.\n",getpgid(0));
    setpgid(getpid(),getppid()); // 改变父进程的组id为父进程的父进程
    printf("The Group ID of parent is changed to %d.\n",getpgid(0));

    return 0;
}
输出:
The child process PID is 6171.
The Group ID of child is 6170.
The Group ID of child is changed to 6171.
The parent process PID is 6170.
The parent of parent process PID is 5869.
The Group ID of parent is 6170.
The Group ID of parent is changed to 5869.
(3)、会话期:一个或多个进程组的集合,在用户登录与退出之间的所有进程组都属于一个会话期
函数声明:
建立一个新的会话期
#include <unistd.h>
pid_t setsid(void);
函数返回值:成功返回进程组ID,失败返回-1
注意:进程组组长不能创建会话期
(4)、会话ID:会话首进程的进程组ID
函数声明:
获取会话ID
#include <unistd.h>
pid_t getsid(pid_t pid);
函数参数:进程ID
返回值:成功返回会话ID,失败返回-1,

示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    pid_t pid;

    if ((pid=fork())<0) {
        printf("fork error!");
        exit(1);
    }else if (pid==0) {
        printf("The child process PID is %d.\n",getpid());
        printf("The Group ID of child is %d.\n",getpgid(0));
        printf("The Session ID of child is %d.\n",getsid(0));
        sleep(10);
        setsid(); // 子进程非组长进程,故其成为新会话首进程,且成为组长进程。该进程组id即为会话进程
        printf("Changed:\n");
        printf("The child process PID is %d.\n",getpid());
        printf("The Group ID of child is %d.\n",getpgid(0));
        printf("The Session ID of child is %d.\n",getsid(0));
        sleep(20);
        exit(0);
    }

    return 0;
}
输出:
The child process PID is 6356.
The Group ID of child is 6355.
The Session ID of child is 5869.
Changed:
The child process PID is 6356.
The Group ID of child is 6356.
The Session ID of child is 6356.
在子进程调用setsid之后,子进程成为新会话首进程,且是新会话中的组长进程,进程组ID等于会话ID
(5)、守护进程
守护进程是在后台运行不受控端控制的进程,通常情况下守护进程在系统启动时自动运行 守护进程的名称通常以d结尾,比如sshd、xinetd、crond等。
函数声明:
#include <unistd.h>
int daemon(int nochdir, int noclose);//C库函数
函数参数:
nochdir:=0将当前目录更改至"/", noclose:=0将标准输入、标准输出、标准错误重定向至“/dev/null”;
等于1的话不更改目录,不重定向
返回值:成功返回0,失败返回-1

二、守护进程的创建步骤
(1)、创建子进程,父进程退出
  • 所有工作在子进程中进行
  • 形式上脱离了控制终端
(2)、子进程中创建新会话
  • setsid()函数
  • 使子进程完全独立出来,脱离控制
(3)、改变当前目录为根目录
  • chdir()函数
  • 防止占用可卸载的文件系统
  • 也可以换成其它路径
(4)、重设文件权限掩码
  • umask()函数
  • 防止继承的文件创建屏蔽字拒绝某些权限
  • 增加守护进程灵活性
(5)、关闭文件描述符
  • 继承的打开文件不会用到,浪费系统资源,无法卸载
  • getdtablesize()
  • 返回所在进程的文件描述符表的项数,即该进程打开的文件数目

三、实现自己的daemon函数
示例:
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

#define ERR_EXIT(m) \
        do \
        { \
                perror(m); \
                exit(EXIT_FAILURE); \
        }while(0)
int my_daemon(void);
int main(int argc,char* argv[])
{
        my_daemon();
        while(1)
                printf("aaa");
        return 0;
}
int my_daemon()
{
        pid_t pid;
        if ((pid = fork()) < 0)
                ERR_EXIT("fork error");
        if (pid > 0)
                exit(EXIT_SUCCESS);
        setsid();
        chdir("/");
        umask(0);
        int i = 3;
        while (i >= 0)
                close(i--);
        open("/dev/null",O_RDWR);
        dup(0);
        dup(0);
        return 0;
}
守护进程在控制台没有输出,可用命令查看到程序在后台运行。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值