<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>益友网 &#187; 进程</title>
	<atom:link href="http://www.1uu2.com/archives/tag/%e8%bf%9b%e7%a8%8b/feed" rel="self" type="application/rss+xml" />
	<link>http://www.1uu2.com</link>
	<description>Linux之友</description>
	<lastBuildDate>Sat, 07 Jan 2012 09:01:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2</generator>
		<item>
		<title>Linux操作系统进程-进程的退出</title>
		<link>http://www.1uu2.com/archives/2475</link>
		<comments>http://www.1uu2.com/archives/2475#comments</comments>
		<pubDate>Thu, 29 Dec 2011 02:27:26 +0000</pubDate>
		<dc:creator>Linux之友</dc:creator>
				<category><![CDATA[Linux技巧]]></category>
		<category><![CDATA[进程]]></category>

		<guid isPermaLink="false">http://www.1uu2.com/?p=2475</guid>
		<description><![CDATA[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.唯一的缺点是并不是每个系统都实行了改函数。 代码分析 int main(int argc, char *argv[]) { printf(“Hello world\n”); Write(STDOUT_FILENO, “CC\n”， 3); if (fork() == -1) [...]]]></description>
			<content:encoded><![CDATA[<p>void _exit(int status)</p>
<p>注意点：</p>
<p>1.status表明了进程终止时的状态。当子进程使用_exit()后，父进程如果在用wait()等待子进程，那么wait()将会返回status状态，注意只有status的低8位(0~255)会返回给父进程。通常，我们使用0，表示进程成功返回，非负值表示进程不成功返回。但是，这种约定不是强制的，每个应用程序都可以自己指定。<span id="more-2475"></span></p>
<p>2.虽然返回值可以是0~255，但是我们通常使用0~128。因为在shell编程中，如果一个进程被信号打断，shell会返回128+信号编号。在shell中，这两个值是没有区别的(都是当做进程返回值)，如果我们进程中使用了128~255，那么就无法区别到底是信号打断还是进程自己退出了。</p>
<p>void exit(int status)</p>
<p>注意点：</p>
<p>1.在exit()调用后，退出处理函数(exit handler)首先被执行(这些函数使用atexit()和on_exit()注册)。</p>
<p>2.stdio流缓冲区被刷新。(还有其他资源的清理)</p>
<p>3.最后一步才是调用_exit()退出。</p>
<p>4.在main函数中最后调用return n和调用exit()是相同的作用。如果在main函数最后调用return或不调用任何退出函数，调用main的运行时函数会自动的调用exit()，但是status会变得不确定(在C89中，status可能会是栈中的某个值，或CPU寄存器中的某个值，这要看编译器是怎么使用的。在C99中，要求status必须是0)。</p>
<p>注册退出处理函数</p>
<p>在程序退出之前，我们都会主动地做一些清理的动作，比如把程序缓冲区的数据保存在文件上。通常的做法是在exit()之前，调用一些清理函数。但这种做法的弊端是，在每个可能退出的地方都写上一大堆相同的代码。另外一种方式就是让程序中所有可能退出的点，都全部集中在一个地方处理。这样做的问题是会出现大量的判断是否成功语句，让代码显得不清晰。Linux提供了下面的两个函数来解决这种问题，把所有的清理函数注册进lib库中，当任意一处调用exit()时，系统会自动的调用注册上的清理函数。</p>
<p>int atexit(void (*func)(void))</p>
<p>注意点：</p>
<p>1.可以注册多个函数，并且一个函数也可多次注册。当要调用它们时，是按照FILO顺序执行的。</p>
<p>2.函数注册后，没办法取消注册。</p>
<p>3.清理函数中调用exit()的行为，在SUSv3中没有定义。在linux中，会继续执行剩下的清理函数。但在某些系统中，可能出现死循环。</p>
<p>4.子进程会继承父进程中的清理函数。</p>
<p>#define _BSD_SOURCE</p>
<p>int on_exit(void (*func)(int, void *)， void *arg)</p>
<p>注意点：</p>
<p>1. on_exit()是atexit()的改良版。在on_exit()中，可以通过func中的int参数知道exit()的退出状态;同一个func可以根据arg的不同，执行不同的代码。</p>
<p>2.唯一的缺点是并不是每个系统都实行了改函数。</p>
<p>代码分析</p>
<p>int main(int argc, char *argv[])</p>
<p>{</p>
<p>printf(“Hello world\n”);</p>
<p>Write(STDOUT_FILENO, “CC\n”， 3);</p>
<p>if (fork() == -1)</p>
<p>exit(1);</p>
<p>exit(0);</p>
<p>}</p>
<p>当在终端执行该程序时，输出入下：</p>
<p>Hello World</p>
<p>CC</p>
<p>当把文字输出到文件时，文件中保存的文字如下：</p>
<p>CC</p>
<p>Hello World</p>
<p>Hello World</p>
<p>分析：当把文字输出到终端时，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”刷新到内核缓冲区中。</p>
<p>来源:中国IT实验室  佚名</p>
]]></content:encoded>
			<wfw:commentRss>http://www.1uu2.com/archives/2475/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

