• 守护进程


    守护进程
    进程组是一组进程的集合,进程组由进程组PID表示
    每个进程除了进程id之外,还必须有一个进程组id,即必须属于某个进程组
    每个进程组都有一个组长,其进程id就作为进程组id,它不受进程组长的退出影响
    一般来说,一个终端一般是进程组长。

    会话期是由一个或多个进程组组成的集合
    一个会话期开始于用户登录,结束于用户退出。在此期间用户运行的的所有进程都属于这个会话期。

    创建守护进程基本步骤
    1.创建子进程
    在终端输入命令执行用户程序时,该进程成为父进程,它此时受控制终端即创建该进程的控制终端控制,通过它创建子进程
    让子进程脱离该终端的控制:子进程执行守护进程需要执行的代码,然后让父进程退出,此时子进程的父进程变为了系统的Init进程。
    当父进程先于子进程退出,子进程成为孤儿进程。
    在linux系统中,每当系统发现一个孤儿进程后,就会自动由1号进程(init进程) 收养它。
    每个进程在创建时都有其自身的进程组、会话期及所属的控制终端,当创建子进程时,子进程复制父进程的这些属性,因此父子进程属于同一个进程组、会话期及控制终端
    2.让子进程脱离该终端的控制。当执行setsid()系统调用,使其脱离原终端控制。它创建一个新的会话并让调用它的进程成为该会话的组长,主要的3个作用
    2.1 让进程摆脱原会话的控制
    2.2 让进程摆脱原进程组的控制
    2.3 让进程摆脱原控制终端的控制
    setsid()系统调用
    3.改变当前目录为根目录
    每个进程在执行时,都保存当前执行目录的信息。子进程也继承父进程的该信息
    由于在进程运行过程中,当前目录所在的文件系统是不能卸载的,
    这对以后的使用会造成诸多的麻烦(如用户要对不使用的目录进行卸载操作,由于该目录还在被守护进程使用,所以umount出错,导致该目录不能被卸载)
    通常的做法是让系统根目录"/" 作为守护进程的的当前工作目录,会避免上述不必要的问题。当然,如果有特殊需要也可以把当前工作目录换成其它的路劲
    4.修改文件权限掩码
    文件掩码是指屏蔽掉文件权限中的对应位。比如,一个文件的权限掩码是050,其对应的二进制码为000101000 表示屏蔽文件用户组用户读和执行的权限
    由于新建子进程继承父进程的文件权限掩码,这就给该子进程操作文件带来诸多麻烦,因此,把文件权限掩码设置成0,即取消子进程对文件操作的限制,
    从而大大增强该守护进程的灵活性,即调用umask(0)
    5.关闭文件描述符
    同文件掩码一样,新建的子进程从父进程继承已经打开的文件描述符。这些被打开的文件描述符可能永远不会被守护进程读写,但它们同样耗费系统资源,
    而且可能导致文件系统无法卸载。既然守护进程与控制终端失去了联系,因此与控制终端相关的文件描述符就不会被使用,如:文件描述符为 0,1,2(输入,输出和出错)
    等文件描述符就不会被使用,失去存在的意义,要关闭它们,可使用close(fd)方法

    示例

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <time.h>
    
    #define MAXFILE 65535
    char *timestr();
    int main(){
        pid_t pc;
        char wtr[100];
        int i,fd,len;
        char *buf ="hello everybody!";
        len=strlen(buf);
        pc=fork();
        if(pc<0){
            printf("fork err
    ");
            exit(1);
        }
        if(pc>0) exit(0);
        
    
        setsid();
        chdir("/");
        umask(0);
        for(i=0;i<MAXFILE;i++){
            while(1){
                if(fd= open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600)<0){
                    perror("open");
                    exit(1);
                }
                sprintf(wtr, "%s-%s
    ",buf,timestr());
                write(fd,wtr,strlen(wtr)+1);
                close(fd);
                sleep(2);
            }
            
        }
    }
    
    char *timestr(){
        time_t timep;
        static char timestr[50];
          struct tm *p;
          time(&timep);
          p = gmtime(&timep);
          sprintf(timestr,"%d:%d:%d", p->tm_hour, p->tm_min, p->tm_sec);
          return timestr;
    }

    运行后

    [root@centos1 c]# ./daemon
    hello everybody!-11:39:41
    [root@centos1 c]# ^C
    [root@centos1 c]# tail -f /tmp/daemon.log
    hello everybody!-11:39:43
    hello everybody!-11:39:45
    hello everybody!-11:39:47
    hello everybody!-11:39:49
    hello everybody!-11:39:51
    hello everybody!-11:39:53
    hello everybody!-11:39:55

    目标

    创建新会话

    头文件

    #include <unistd.h>;#include <sys/types.h>

    函数原型

    pid_t pid=setsid(void)

    返回值

    出错,返回-1

    成功,返回该进程组的pid

  • 相关阅读:
    Delphi 农历算法
    Installing Custom Maps for L4D
    双网卡,上网走外网网卡,内网走内网网卡设置
    L4D的指令合集
    两个RGB的颜色半透明混色算法
    中国省级行政区划变动情况
    Win7编程:在按钮中加入管理员权限运行
    教你快速识别手机质量的好坏
    如何利用预编译指令来判断Delphi 的版本?
    在.NET中读写INI文件 ——兼谈正则表达式的应用
  • 原文地址:https://www.cnblogs.com/HKUI/p/9097156.html
Copyright © 2020-2023  润新知