• (转载)Linux--进程组、会话、守护进程


    (蓝色字体是我自己的补充--话绕了远路)

    进程组

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

    (getpgid() returns the PGID of the process specified by pid. If pid is zero, the process ID of the calling process is used.)

    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. ",getpid());
    12 printf("The Group ID is %d. ",getpgrp());
    13 printf("The Group ID is %d. ",getpgid(0));
    14 printf("The Group ID is %d. ",getpgid(getpid()));
    15 exit(0);
    16 }
    17
    18 sleep(3);
    19 printf("The parent process PID is %d. ",getpid());
    20 printf("The Group ID is %d. ",getpgrp());
    21
    22 return 0;
    23 }
    复制代码

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

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

    setpgid() sets the PGID of the process specified by pid to pgid. If pid is zero, then the process ID of the calling process is used. If pgid is zero, then the PGID of the process specified by pid is made the same as its process ID. If setpgid() is used to move a process from one process group to another , both process groups must be part of the same session. In this case, the pgid specifies an existing process group to be joined and the session ID of that group must match the session ID of the joining process.

    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. ",getpid());
    13 printf("The Group ID of child is %d. ",getpgid(0)); // 返回组id
    14 sleep(5);
    15 printf("The Group ID of child is changed to %d. ",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. ",getpid());
    24 printf("The parent of parent process PID is %d. ",getppid());
    25 printf("The Group ID of parent is %d. ",getpgid(0));
    26 setpgid(getpid(),getppid()); // 改变父进程的组id为父进程的父进程
    27 printf("The Group ID of parent is changed to %d. ",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. ",getpid());
    13 printf("The Group ID of child is %d. ",getpgid(0));
    14 printf("The Session ID of child is %d. ",getsid(0));
    15 sleep(10);
    16 setsid(); // 子进程非组长进程,故其成为新会话首进程,且成为组长进程。该进程组id即为会话进程
    17 printf("Changed: ");
    18 printf("The child process PID is %d. ",getpid());
    19 printf("The Group ID of child is %d. ",getpgid(0));
    20 printf("The Session ID of child is %d. ",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. ";
    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! ");
    30 exit(1);
    31 }
    32 // 将buf写到fd中
    33 write(fd,buf,strlen(buf)+1);
    34 close(fd);
    35 sleep(10);
    36 printf("Never output! ");
    37 }
    38
    39 return 0;
    40 }
    复制代码

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

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

  • 相关阅读:
    Mapreduce的Job运行流程
    Mapreduce的job提交流程
    Hadoop之hdfs
    Java之垃圾回收机制
    Java中线程死锁问题
    删除数据表重复元素方法
    JAVA
    php篇一 之上传文件
    php篇二 之微信公众号开发
    android + php 后台开发
  • 原文地址:https://www.cnblogs.com/24zyt/p/6845315.html
Copyright © 2020-2023  润新知