#include<stdio.h>
#include<stdlib.h>
定义函数
void perror(const char *s); perror ("open_port");函数说明
perror ( )用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 错误 (stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量error 的值来决定要输出的字符串。在库函数中有个error变量,每个error值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了error的值。perror函数只是将你输入的一些信息和现在的error所对应的错误一起输出。
exit:(#include <stdlib.h>)
在C语言的main函数中我们通常使用return (0);这样的方式返回一个值。但这是限定在非void情况下的,也就是非void main()这样的形式。 exit()通常是用在子程序中用来终结程序用的,使用后程序自动结束,跳出操作系统。
exit(0) 表示程序正常退出,
exit(1)/exit(-1)表示程序异常退出。
exit() 结束当前进程/当前程序/,在整个程序中,只要调用 exit ,就结束。
但在如果把exit用在main内的时候无论main是否定义成void返回的值都是有效的,并且exit不需要考虑类型,exit(1)等价于return (1) 。
例如:
#include<stdlib.h>
int main()
{
exit (1);//等价于return (1);
}
exit()是一个函数 ,结束一个进程,它将删除进程使用的内存空间,同时把错误信息返回父进程,在父进程中wait系统调用将接受到此返回信息。
进程就好比人一样有其生命,我们通过fork()函数来创建一个进程,那么我们又是如何来中止进程呢。
进程退出
1.在Linux中任何让一个进程退出
进程退出表示进程即将结束。在Linux中进程退出分为了正常退出和异常退出两种。
1>正常退出
a. 在main()函数中执行return 。
b.调用exit()函数 #include <stdlib.h> void exit(int status)
c.调用_exit()函数 #include <unistd.h> void _exit(int status)
status 是一个整型的参数,可以利用这个参数传递进程结束时的状态。一般来说,
0 表示正常结束;其他的数值表示出现了错误,进程非正常结束。
在实际编程时,可以用 wait 系统调用接收子进程的返回值,从而针对不同的情况
进行不同的处理
2>异常退出
a.调用about函数
b.进程收到某个信号,而该信号使程序终止。
Tiger-John说明:
不管 是那种 退出方式,系统最终都会执行内核中的同一代码。这段代码用来关闭进程所用已打开的文件描述符,释放它所占用的内存和其他资源。
3>比较以上几种退出方式的不同点
(1)exit和return 的区别:
a.exit是一个函数,有参数。exit执行完后把控制权交给系统
b.return是函数执行完后的返回。renturn执行完后把控制权交给调用函数。
(2)exit和abort的区别:
a.exit是正常终止进程
b.about是异常终止。
现在我们重点了解exit()和_exit()函数
2.exit()和_exit()的学习
1>exit和_exit函数都是用来终止进程的。
当程序执行到exit或_exit时,系统无条件的停止剩下所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。
2>exit在头文件stdlib.h中声明,而_exit()声明在头文件unistd.h中声明。 exit中的参数exit_code为0代表进程正常终止,若为其他值表示程序执行过程中有错误发生。
3>exit()和_exit()的区别:
a._exit()执行后立即返回给内核,而exit()要先执行一些清除操作,然后将控制权交给内核。
b. 调用_exit函数时,其会关闭进程所有的文件描述符,清理内存以及其他一些内核清理函数,但不会刷新流(stdin, stdout, stderr ...). exit函数是在_exit函数之上的一个封装,其会调用_exit,并在调用之前先刷新流。
Tiger-John说明:
exit()函数与_exit()函数最大区别就在于exit()函数在调用exit系统之前要检查文件的打开情况,把文件缓冲区的内容写回文件。 由于Linux的标准函数库中,有一种被称作“缓冲I/O”的操作,其特征就是对应每一个打开的文件,在内存中都有一片缓冲区。每次读文件时,会连续的读 出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区读取;同样,每次写文件的时候也仅仅是写入内存的缓冲区,等满足了一定的条件(如达到了一定数 量或遇到特定字符等),再将缓冲区中的内容一次性写入文件。这种技术大大增加了文件读写的速度,但也给编程代来了一点儿麻烦。比如有一些数据,认为已经写 入了文件,实际上因为没有满足特定的条件,它们还只是保存在缓冲区内,这时用_exit()函数直接将进程关闭,缓冲区的数据就会丢失。因此,要想保证数 据的完整性,就一定要使用exit()函数。
c . 通过一个函数实例来看看它们之间的区别:
函数实例1 : exit.c
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 int main()
5 {
6 printf("using exit----\n");
7 printf("This is the content in buffer\n");
8 exit(0);
9 }
函数经过调试后
执行结果为:
using exit----
This is the content in buffer
函数实例2:_exit.c
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main(void)
5 {
6 printf("using _exit--\n");
7 printf("This is the content in buffer");
8 _exit(0);
9 }
函数经过调试后
$ gcc _exit.c -o _exit
$ ./_exit
执行结果为 :
using _exit--
Tiger-John说明:
1.printf函数就是使用缓冲I/O的方式,该函数在遇到“\n”换行符时自动的从缓冲区中将记录读出。所以exit()将缓冲区的数据写完后才退出,而_exit()函数直接退出。
2.大家也可以把函数实例2中的printf("This is the content in buffer");改为printf("This is the content in buffer\n")(即在printf中最后加一个\n看运行结果是什么,为什么会产生这样的结果呢?)
小知识
在一个进程调用了 exit 之后,该进程并不马上就完全消失,而是留下一个称为僵尸进程
(Zombie)的数据结构。僵尸进程是一种非常特殊的进程,它几乎已经放弃了所有内存空间,
没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出
状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。
wait
wait 函数是用于使父进程(也就是调用 wait 的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。
如果该父进程没有子进程或者他的子进程已经结束, wait则就会立即返回。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status)
waitpid
waitpid 的作用和 wait 一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的 wait 功能,也能支持作业控制。实际上 wait 函数只是 waitpid 函数的一个特例,在 Linux 内部实现 wait 函数时直接调用的就是 waitpid 函数。
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options)