Linux Daemon & 单例模式 设计与实现

来源:互联网 发布:程序员 判刑 编辑:程序博客网 时间:2024/06/05 20:04

#PS:要转载请注明出处,本人版权所有

#PS:这个只是 《 我自己 》理解,如果和你的

#原则相冲突,请谅解,勿喷

单例模式

原理

创建一个保存进程名的文件,利用linux的文件锁来判断文件是否加锁来判断是否已有相同的程序运行。

例子

int CheckIsSingleton(int *fd){    struct flock loglock;      char nowpid[10];    int num;    if (0 > (*fd = open(LOCK_FILE_NAME, O_WRONLY | O_CREAT, 0600)))    {        perror("open lock file failed!");        return -1;    }    /*struct flock {               ...               short l_type;    // Type of lock: F_RDLCK,                                   //F_WRLCK, F_UNLCK                short l_whence;  // How to interpret l_start:                                //SEEK_SET, SEEK_CUR, SEEK_END                off_t l_start;   // Starting offset for lock                off_t l_len;     // Number of bytes to lock                pid_t l_pid;     // PID of process blocking our lock                                  // (set by F_GETLK and F_OFD_GETLK)                ...           };       As well as being removed by an explicit F_UNLCK, record locks are auto‐       matically released when the process terminates.*/    memset(&loglock, 0, sizeof(struct flock));    loglock.l_type = F_WRLCK;    loglock.l_whence = SEEK_SET;    if ( 0 >  fcntl(*fd, F_GETLK, &loglock) ){//检查是否能够加F_WRLCK锁,不能够确认文件是否有锁。            close(*fd);            perror("fcntl F_WRLCK failed");            _exit(-1);    }    else{        if ( loglock.l_type != F_UNLCK){            close(*fd);            write(2,"check F_WRLCK failed\n",sizeof("check F_WRLCK failed\n"));//stdout was closed!!!            write(2,"The same process is running\n",sizeof("The same process is running\n"));            _exit(-1);        }    }    loglock.l_type = F_WRLCK;    loglock.l_start = 0;  //从文件开始加锁    loglock.l_whence = SEEK_SET;      loglock.l_len = 0; //加锁整个文件    if ( 0 >  fcntl(*fd, F_SETLK, &loglock) ){        close(*fd);        perror("fcntl F_WRLCK failed");        printf("The same process is running\n");        _exit(-1);    }    num = sprintf(nowpid, "%d",getpid());    write(*fd, nowpid, num);    return 0;}

Daemon 简单设计

原理

1 利用fork来实现。setsid使当前子进程成为新的进程组长,在使用fork使其与终端脱离,设置工作目录,设置文件掩码
2 利用系统提供的daemon()(此调用来至于glibc)来完成功能。(底层使用fork来实现)

例子

void CreateDaemonProcess_daemon()//根据daemon函数的源码来看,后面补充了一个fork比较安全{    /*       The daemon() function is for programs wishing to detach themselves from       the controlling terminal and run in the background as system daemons.       If nochdir is zero, daemon()  changes  the  process's  current  working       directory  to  the root directory ("/"); otherwise, the current working       directory is left unchanged.       If noclose is zero, daemon() redirects standard input, standard  output       and  standard  error  to  /dev/null;  otherwise, no changes are made to       these file descriptors.intdaemon(nochdir, noclose)    int nochdir, noclose;{    int fd;    switch (__fork()) {    case -1:        return (-1);    case 0:        break;    default:        _exit(0);    }    if (__setsid() == -1)        return (-1);    if (!nochdir)        (void)__chdir("/");    if (!noclose) {        struct stat64 st;        if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1            && (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0)            == 0)) {            if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR                && (st.st_rdev                == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR))#endif                ) {                (void)__dup2(fd, STDIN_FILENO);                (void)__dup2(fd, STDOUT_FILENO);                (void)__dup2(fd, STDERR_FILENO);                if (fd > 2)                    (void)__close (fd);            } else {                // We must set an errno value since no                 //  function call actually failed.                  close_not_cancel_no_status (fd);                __set_errno (ENODEV);                return -1;            }        } else {            close_not_cancel_no_status (fd);            return -1;        }    }    return (0);}*/    if (0 > daemon(0, 0))    {        perror("daemon call failed!");        _exit(-1);    }    //setsid();    // int fd;    // if ( 0 > (fd = open("/dev/tty", O_RDWR )) ){    //     perror("open tty failed!");    //     _exit(-1);    // }    // if ( ioctl(fd, TIOCNOTTY, NULL) < 0){    //     perror("ioctl TIOCNOTTY failed!");    //     close(fd);    //     _exit(-1);    // }    // close(fd);    int pid;    pid = fork();    if (pid == -1)    {        perror("fork first error!");    }    else if (pid > 0)    { //parent 1        _exit(1);    }    else    { //child pid==0    }    return;}void CreateDaemonProcess_Fork(){    pid_t pid, pid1, pid2;    pid = fork();    if (pid == -1)    {        perror("fork first error!");    }    else if (pid > 0)    { //parent 1        _exit(1);    }    else    { //child pid==0        if (0 > (pid1 = setsid()))        {            perror("setsid() call failed!");            _exit(-1); //        }        else        {            printf("New session id is %d\n", pid1);        }        pid2 = fork();        if (pid2 == -1)        {            perror("fork second error!");        }        else if (pid2 > 0)        { //parent            _exit(1);        }        else        {            chdir("/"); //change current working directory            umask(0);            return;        }    }}

说明:

1 双fork的原因是进程组长会开启终端。而我们的daemon程序是不需要终端的。
2 文件掩码用于设置默认的文件权限。
3 子进程会继承父进程的大部分属性,包括已打开文件描述符、文件掩码、工作目录等待,这些根据需求处理。

#PS:请尊重原创,不喜勿喷

#PS:要转载请注明出处,本人版权所有.

有问题请留言,看到后我会第一时间回复

原创粉丝点击