freeeyes 发表于 2013-9-24 09:20:51

Linux后台进程挂起通用做法

最近看了一些Twitter的一些开源项目,吸收到了很多好的想法。
其实老外似乎不是很喜欢C++,C的底层比较多。不过我觉得倒是无所谓,所谓的C坑少,大多数是因为以对象的方法设计了过程式代码。毕竟,这个世界,并不是只有对象存在的方式,合理的搭配,才是能发挥最强的开发方式,还是那句话,代码不重要,重要的是想法。
比如,抠出一个很通用的进程后台挂起方法,一个函数搞定,一般情况下不需要改动这里的代码,只要调用一下即可。
static int daemonize()
{
        pid_t pid, sid;
        int fd;

        pid = fork();
        switch (pid) {
        case -1:
                printf("fork() failed: %s", strerror(errno));
                return -1;

        case 0:
                break;
        default:
                _exit(0);
        }

        sid = setsid();
        if (sid < 0) {
                printf("setsid() failed: %s", strerror(errno));
                return -1;
        }

        if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
                printf("signal(SIGHUP, SIG_IGN) failed: %s", strerror(errno));
                return -1;
        }

        int status = chdir("/");
        if (status < 0) {
                printf("chdir(\"/\") failed: %s", strerror(errno));
                return -1;
        }

        umask(0);

        fd = open("/dev/null", O_RDWR);
        if (fd < 0) {
                printf("open(\"/dev/null\") failed: %s", strerror(errno));
                return -1;
        }

        status = dup2(fd, STDIN_FILENO);
        if (status < 0) {
                printf("dup2(%d, STDIN) failed: %s", fd, strerror(errno));
                close(fd);
                return -1;
        }

        status = dup2(fd, STDOUT_FILENO);
        if (status < 0) {
                printf("dup2(%d, STDOUT) failed: %s", fd, strerror(errno));
                close(fd);
                return -1;
        }

        status = dup2(fd, STDERR_FILENO);
        if (status < 0) {
                printf("dup2(%d, STDERR) failed: %s", fd, strerror(errno));
                close(fd);
                return -1;
        }

        if (fd > STDERR_FILENO) {
                status = close(fd);
                if (status < 0) {
                        printf("close(%d) failed: %s", fd, strerror(errno));
                        return -1;
                }
        }

        return 0;   
}
看,非常漂亮吧,很实用。
在这里记录一下。
这里要说一下ACE的daemonize,至今比这个过程少了几步,最重要的是/dev/null没有被设置。
如果在程序有大量输出的时候(比如printf),CPU占用率会被吃掉不少,起不到提高效率的作用。所以我都用这个函数替换了ace的daemonize。
希望ACE在以后的版本中改进。
看看ACE 在6.0.0里面干了什么。。
以下是ACE源代码:
int
ACE::daemonize (const ACE_TCHAR pathname[],
                bool close_all_handles,
                const ACE_TCHAR program_name[])
{
ACE_TRACE ("ACE::daemonize");
#if !defined (ACE_LACKS_FORK)
pid_t pid = ACE_OS::fork ();

if (pid == -1)
    return -1;
else if (pid != 0)
    ACE_OS::exit (0); // Parent exits.

// 1st child continues.
ACE_OS::setsid (); // Become session leader.

ACE_OS::signal (SIGHUP, SIG_IGN);

pid = ACE_OS::fork (program_name);

if (pid != 0)
    ACE_OS::exit (0); // First child terminates.

// Second child continues.

if (pathname != 0)
    // change working directory.
    ACE_OS::chdir (pathname);

ACE_OS::umask (0); // clear our file mode creation mask.

return 0;
#else
ACE_UNUSED_ARG (pathname);
ACE_UNUSED_ARG (close_all_handles);
ACE_UNUSED_ARG (program_name);

ACE_NOTSUP_RETURN (-1);
#endif /* ACE_LACKS_FORK */
}
少了STDIN_FILENO STDOUT_FILENO STDERR_FILENO 和 dev/null
这几个参数都是很关键的参数,不过我个人觉得未必是ACE的疏忽,只是我个人觉得应该补上。更好的提供效能,毕竟,后台输出不重定向是无意义的,别人也看不见。
页: [1]
查看完整版本: Linux后台进程挂起通用做法