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

#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.

int
daemon(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:要转载请注明出处,本人版权所有.

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值