Chinaunix首页 | 论坛 | 博客
  • 博客访问: 526501
  • 博文数量: 235
  • 博客积分: 1209
  • 博客等级: 少尉
  • 技术积分: 1417
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-19 19:59
文章分类

全部博文(235)

文章存档

2012年(107)

2011年(128)

分类:

2011-12-29 07:31:46

原文地址:Linux进程-进程的退出 作者:ddbddb1

void _exit(int status)

注意点:

1.status表明了进程终止时的状态。当子进程使用_exit()后,父进程如果在用wait()等待子进程,那么wait()将会返回status状态,注意只有status的低8位(0~255)会返回给父进程。通常,我们使用0,表示进程成功返回,非负值表示进程不成功返回。但是,这种约定不是强制的,每个应用程序都可以自己指定。

2.虽然返回值可以是0~255,但是我们通常使用0~128。因为在shell编程中,如果一个进程被信号打断,shell会返回128+信号编号。在shell中,这两个值是没有区别的(都是当做进程返回值),如果我们进程中使用了128~255,那么就无法区别到底是信号打断还是进程自己退出了。

 

void exit(int status)

注意点:

1.exit()调用后,退出处理函数(exit handler)首先被执行(这些函数使用atexit()on_exit()注册)。

2.stdio流缓冲区被刷新。(还有其他资源的清理)

3.最后一步才是调用_exit()退出。

4.main函数中最后调用return n和调用exit()是相同的作用。如果在main函数最后调用return或不调用任何退出函数,调用main的运行时函数会自动的调用exit(),但是status会变得不确定(在C89中,status可能会是栈中的某个值,或CPU寄存器中的某个值,这要看编译器是怎么使用的。在C99中,要求status必须是0)。

 

注册退出处理函数

在程序退出之前,我们都会主动地做一些清理的动作,比如把程序缓冲区的数据保存在文件上。通常的做法是在exit()之前,调用一些清理函数。但这种做法的弊端是,在每个可能退出的地方都写上一大堆相同的代码。另外一种方式就是让程序中所有可能退出的点,都全部集中在一个地方处理。这样做的问题是会出现大量的判断是否成功语句,让代码显得不清晰。Linux提供了下面的两个函数来解决这种问题,把所有的清理函数注册进lib库中,当任意一处调用exit()时,系统会自动的调用注册上的清理函数。


int atexit(void (*func)(void))

注意点:

1.可以注册多个函数,并且一个函数也可多次注册。当要调用它们时,是按照FILO顺序执行的。

2.函数注册后,没办法取消注册。

3.清理函数中调用exit()的行为,在SUSv3中没有定义。在linux中,会继续执行剩下的清理函数。但在某些系统中,可能出现死循环。

4.子进程会继承父进程中的清理函数。

 

#define _BSD_SOURCE

int on_exit(void (*func)(int, void *), void *arg)

注意点:

1. on_exit()atexit()的改良版。在on_exit()中,可以通过func中的int参数知道exit()的退出状态;同一个func可以根据arg的不同,执行不同的代码。

2.唯一的缺点是并不是每个系统都实行了改函数。

 

代码分析

  1. int main(int argc, char *argv[])
  2. {
  3.        printf(“Hello world\n”);
  4.        Write(STDOUT_FILENO, “CC\n”, 3);
  5.  
  6.        if (fork() == -1)
  7.               exit(1);

  8.        exit(0);
  9. }

当在终端执行该程序时,输出入下:

       Hello World

       CC

当把文字输出到文件时,文件中保存的文字如下:

       CC

       Hello World

       Hello World

 

分析:当把文字输出到终端时,stdio函数组是按行输出。而输出到文件时,是按照块输出。也就是说,在输出到文件时,printf()函数把”Hello World\n”输入进用户stdio缓冲区,但是没有达到输出块的大小。write函数直接把“CC\n”输出到内核缓冲区,而不是用户进程的缓冲区。接下来fork()出一个子进程,子进程的用户缓冲区是拷贝父进程的,也就是说在子进程中的stdio缓冲区中也存在一个”Hello World\n”,但是内核缓冲区是不会拷贝的。CC出现在Hello World前面是因为执行完write()后,CC已近在内核缓冲区中,而printf()后“Hello World”还在用户stdio缓冲区中,直到执行了exit(),才把“Hello World”刷新到内核缓冲区中。
阅读(846) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~