Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1438784
  • 博文数量: 704
  • 博客积分: 10140
  • 博客等级: 上将
  • 技术积分: 6230
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-15 20:41
文章分类

全部博文(704)

文章存档

2013年(1)

2012年(16)

2011年(536)

2010年(151)

分类: LINUX

2010-07-30 13:45:17

POSIX线程库的API中有分离线程的API:

       #include <pthread.h>

       int pthread_detach(pthread_t thread);

       int pthread_attr_setdetachstate (pthread_attr_t *__attr,
                                        int __detachstate)


如果一个线程调用了这个函数,那么当这个线程终止的时候,和它相关的系统资源将被自动释放,系统不用也不能用pthread_join()等待其退出。有的时候分离线程更好些,因为它潜在地减少了一个线程回收的同步点,并且pthread_join()这个API确实也是相当地难用。

一般情况下进程终止的时候,和它相关的系统资源也并不是主动释放的,而是进入一种通常称为“僵尸”(zombie)的状态。它所占有的资源一直被系统保留,直到它的父进程(如果它直接的父进程先于它去世,那么它将被init进程所收养,这个时候init就是它的父进程)显式地调用wait系列函数为其“收尸”。为了让父进程尽快知道它去世的消息,它会在它死去的时候通过向父进程发送SIGCHLD信号的方式向其“报丧”,父进程通常安装有类似下面的 SIGCHLD信号处理函数:

void reap_zombie(int signo)
{
        int errno_old = errno;

        while (waitpid(-1, NULL, WNOHANG) > 0)
                ;

        errno = errno_old;
}


如果只是为了为子进程“收尸”,以上代码足矣!另一方面,如果父进程对子进程的终止状态没有任何兴趣,那么以上代码无疑又会引入无谓的复杂度,并且还有潜在的同步瓶颈。如果进程能够像处于分离状态的线程那样死得干干净净,那就完美了!

POSIX标准为我们考虑地可谓十分周到,下面是 sigaction(2)的手册页中的一段话:

       POSIX.1-1990 disallowed setting the action for SIGCHLD to SIG_IGN.  POSIX.1-2001 allows this  possibility,
       so  that ignoring SIGCHLD can be used to prevent the creation of zombies (see wait(2)).  Nevertheless, the
       historical BSD and System V behaviours for ignoring SIGCHLD differ, so that the only  completely  portable
       method  of ensuring that terminated children do not become zombies is to catch the SIGCHLD signal and per-
       form a wait(2) or similar.

从中我们可以得知POSIX.1-2001允许将SIGCHLD 的信号处理函数设置为SIG_IGN,这时子进程退出的时候将不会进入僵尸状态,并且它所占用的系统资源将被操作系统自动回收:

signal(SIGCHLD, SIG_IGN);


除此之外,你还可以通过将sigaction调用中的flags与上SA_NOCLDWAIT来分离子进程:

                        struct sigaction act;

                        memset(&act, 0, sizeof(act));
                        act.sa_flags |= SA_NOCLDWAIT;
                        sigaction(SIGCHLD, &act, NULL);


以下是我为此所作的测试的代码:


#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void reap_zombie(int signo)
{
        int errno_old = errno;

        while (waitpid(-1, NULL, WNOHANG) > 0)
                ;

        errno = errno_old;
}

int main(int argc, char *argv[])
{
        pid_t pid;

        if (argc == 2) {
                if (strcmp(argv[1], "signal") == 0)
                        signal(SIGCHLD, SIG_IGN);
                else if (strcmp(argv[1], "handle") == 0)
                        signal(SIGCHLD, reap_zombie);
                else {
                        struct sigaction act;

                        memset(&act, 0, sizeof(act));
                        act.sa_flags |= SA_NOCLDWAIT;
                        sigaction(SIGCHLD, &act, NULL);
                }
        }
        pid = fork();
        if (pid == 0) {
                fprintf(stderr, "I am child\n");
                sleep(1);
                fprintf(stderr, "Child exits\n");

                return EXIT_SUCCESS;
        }
        sleep(2);
        system("ps -el | grep t_process");
        wait(NULL);
        perror("wait");

        return
EXIT_SUCCESS;
}


代码的实际运行情况如下所示:

[xiaosuo@Ulard-iolo ~]$ uname -a
Linux Ulard-iolo 2.6.20-1.2316.fc5 #1 Fri Apr 27 19:49:38 EDT 2007 i686 i686 i386 GNU/Linux
[xiaosuo@Ulard-iolo ~]$ gcc t_process_detach.c -o t_process_detach
[xiaosuo@Ulard-iolo ~]$ ./t_process_detach
I am child
Child exits
0 S   506 17595 16594  0  78   0 -   361 wait   pts/1    00:00:00 t_process_detac
1 Z   506 17596 17595  0  78   0 -     0 exit   pts/1    00:00:00 t_process_detac
wait: Success
[xiaosuo@Ulard-iolo ~]$ ./t_process_detach signal
I am child
Child exits
0 S   506 17602 16594  0  75   0 -   360 wait   pts/1    00:00:00 t_process_detac
wait: No child processes
[xiaosuo@Ulard-iolo ~]$ ./t_process_detach handle
I am child
Child exits
0 S   506 17609 16594  0  75   0 -   361 wait   pts/1    00:00:00 t_process_detac
wait: No child processes
[xiaosuo@Ulard-iolo ~]$ ./t_process_detach sigaction
I am child
Child exits
0 S   506 17616 16594  0  75   0 -   360 wait   pts/1    00:00:00 t_process_detac
wait: No child processes

可见,我们的目的达到了。

注意:在比较老的系统上,以上技巧可能并不可用。
阅读(1022) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~