• Linux进程组、会话、守护进程


    进程组
      一个或多个进程的集合
      进程组ID: 正整数
      两个函数
      getpgid(0)=getpgrp()

    eg:显示子进程与父进程的进程组id

     1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <unistd.h>
    4
    5 int main() {
    6 pid_t pid;
    7
    8 if ((pid=fork())<0) {
    9 printf("fork error!");
    10 }else if (pid==0) {
    11 printf("The child process PID is %d.\n",getpid());
    12 printf("The Group ID is %d.\n",getpgrp());
    13 printf("The Group ID is %d.\n",getpgid(0));
    14 printf("The Group ID is %d.\n",getpgid(getpid()));
    15 exit(0);
    16 }
    17
    18 sleep(3);
    19 printf("The parent process PID is %d.\n",getpid());
    20 printf("The Group ID is %d.\n",getpgrp());
    21
    22 return 0;
    23 }

    进程组id = 父进程id,即父进程为组长进程

    组长进程
      组长进程标识: 其进程组ID==其进程ID
      组长进程可以创建一个进程组,创建该进程组中的进程,然后终止
      只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关
      进程组生存期: 进程组创建到最后一个进程离开(终止或转移到另一个进程组)
     
    一个进程可以为自己或子进程设置进程组ID
      setpgid()加入一个现有的进程组或创建一个新进程组

    eg:父进程改变自身和子进程的组id

     1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <unistd.h>
    4
    5 int main() {
    6 pid_t pid;
    7
    8 if ((pid=fork())<0) {
    9 printf("fork error!");
    10 exit(1);
    11 }else if (pid==0) {
    12 printf("The child process PID is %d.\n",getpid());
    13 printf("The Group ID of child is %d.\n",getpgid(0)); // 返回组id
    14 sleep(5);
    15 printf("The Group ID of child is changed to %d.\n",getpgid(0));
    16 exit(0);
    17 }
    18
    19 sleep(1);
    20 setpgid(pid,pid); // 改变子进程的组id为子进程本身
    21
    22 sleep(5);
    23 printf("The parent process PID is %d.\n",getpid());
    24 printf("The parent of parent process PID is %d.\n",getppid());
    25 printf("The Group ID of parent is %d.\n",getpgid(0));
    26 setpgid(getpid(),getppid()); // 改变父进程的组id为父进程的父进程
    27 printf("The Group ID of parent is changed to %d.\n",getpgid(0));
    28
    29 return 0;
    30 }

    会话: 一个或多个进程组的集合
      开始于用户登录
      终止与用户退出
      此期间所有进程都属于这个会话期

    建立新会话:setsid()函数
      该调用进程是组长进程,则出错返回
        先调用fork, 父进程终止,子进程调用
      该调用进程不是组长进程,则创建一个新会话
        •该进程变成新会话首进程(session header)
        •该进程成为一个新进程组的组长进程。
        •该进程没有控制终端,如果之前有,则会被中断
    组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程...

    会话ID:会话首进程的进程组ID
    获取会话ID: getsid()函数

     1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <unistd.h>
    4
    5 int main() {
    6 pid_t pid;
    7
    8 if ((pid=fork())<0) {
    9 printf("fork error!");
    10 exit(1);
    11 }else if (pid==0) {
    12 printf("The child process PID is %d.\n",getpid());
    13 printf("The Group ID of child is %d.\n",getpgid(0));
    14 printf("The Session ID of child is %d.\n",getsid(0));
    15 sleep(10);
    16 setsid(); // 子进程非组长进程,故其成为新会话首进程,且成为组长进程。该进程组id即为会话进程
    17 printf("Changed:\n");
    18 printf("The child process PID is %d.\n",getpid());
    19 printf("The Group ID of child is %d.\n",getpgid(0));
    20 printf("The Session ID of child is %d.\n",getsid(0));
    21 sleep(20);
    22 exit(0);
    23 }
    24
    25 return 0;
    26 }

    在子进程中调用setsid()后,子进程成为新会话首进程,且成为一个组长进程,其进程组id等于会话id

    守护进程
      Linux大多数服务都是通过守护进程实现的,完成许多系统任务
      0: 调度进程,称为交换进程(swapper),内核一部分,系统进程
      1: init进程, 内核调用,负责内核启动后启动Linux系统
      没有终端限制
      让某个进程不因为用户、终端或者其他的变化而受到影响,那么就必须把这个进程变成一个守护进程
     
    守护进程编程步骤
      1. 创建子进程,父进程退出
        •所有工作在子进程中进行
        •形式上脱离了控制终端
      2. 在子进程中创建新会话
        •setsid()函数
        •使子进程完全独立出来,脱离控制
      3. 改变当前目录为根目录
        •chdir()函数
        •防止占用可卸载的文件系统
        •也可以换成其它路径
      4. 重设文件权限掩码
        •umask()函数
        •防止继承的文件创建屏蔽字拒绝某些权限
        •增加守护进程灵活性
      5. 关闭文件描述符
        •继承的打开文件不会用到,浪费系统资源,无法卸载
        •getdtablesize()
        •返回所在进程的文件描述符表的项数,即该进程打开的文件数目

     1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <string.h>
    4 #include <unistd.h>
    5 #include <sys/wait.h>
    6 #include <sys/types.h>
    7 #include <fcntl.h>
    8
    9 int main() {
    10 pid_t pid;
    11 int i,fd;
    12 char *buf="This is a daemon program.\n";
    13
    14 if ((pid=fork())<0) {
    15 printf("fork error!");
    16 exit(1);
    17 }else if (pid>0) // fork且退出父进程
    18 exit(0);
    19
    20 setsid(); // 在子进程中创建新会话。
    21 chdir("/"); // 设置工作目录为根
    22 umask(0); // 设置权限掩码
    23 for(i=0;i<getdtablesize();i++) //getdtablesize返回子进程文件描述符表的项数
    24 close(i); // 关闭这些不将用到的文件描述符
    25
    26 while(1) {// 死循环表征它将一直运行
    27 // 以读写方式打开"/tmp/daemon.log",返回的文件描述符赋给fd
    28 if ((fd=open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600))<0) {
    29 printf("Open file error!\n");
    30 exit(1);
    31 }
    32 // 将buf写到fd中
    33 write(fd,buf,strlen(buf)+1);
    34 close(fd);
    35 sleep(10);
    36 printf("Never output!\n");
    37 }
    38
    39 return 0;
    40 }

    因为stdout被关掉了,所以“Never ouput!”不会输出。

    查看/tmp/daemon.log,说明该程序一直在运行



     
     
     
     



     



  • 相关阅读:
    欧拉项目第十题;用筛法做,
    欧拉第十题 求2000000以内的素数之和
    求1000数字中13个相乘最大值
    筛法求10000以内的质数
    判断回文且寻找三位数乘三位数里最大的回文
    分解质因数
    输入一个正整数n,将其转换为二进制后输出。要求定义并调用函数dectobin(n),它的功能是输出
    hdu1863最小生成树krus模板&prim模板
    hdu 3870 最小割转化为最短路径2
    UVALive 3661 最小割转化为最短路径
  • 原文地址:https://www.cnblogs.com/forstudy/p/2427683.html
Copyright © 2020-2023  润新知