前言:在Linux多进程中,在进程结束时,需要释放分配给进程的地址空间以及内核中产生的各种数据结构,这是就需要用到exit()和_exit函数了。
一、exit()与_exit()
exit
函数头文件 #include <stdlib.h>
函数原型 void exit(int status);
函数功能 结束进程,并刷新缓冲区
函数参数 status:退出状态值
_exit()
函数头文件 #include <unistd.h>
函数原型 void _exit(int status);
函数参数 status:进程退出的状态值
注意:exit()是对基于_exit()构建的,属于库函数(用户区)。并且该函数是会刷新缓冲区的。而_exit()是属于系统调用(内核区),简单说就是计算机硬件给了我们一个调用的一个窗口,并不具有刷新缓冲区的功能。
二.使用步骤
1.exit()
代码如下(示例):
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main()
{
pid_t pid = fork(); //创建一个子线程,并返回它的pid
if(pid == -1){ //等于-1意味着创建失败;
perror("fork:");
exit(EXIT_FAILURE);
}else if(pid == 0){ //等于0,子线程开始;
printf("child"); //注意:后面没有换行符;
sleep(2); //休眠2秒,在休眠的过程中不参与对时间片的竞争;
exit(EXIT_SUCCESS); //结束子进程并刷新缓冲区;
}else{ //主线程开始;
printf("parent\n");
sleep(5);
printf("parent end\n");
}
return 0;
}
简单在说一下,在程序开始时,执行主进程还是子进程是根据操作系统的规则来的,并不是绝对的。
还有要注意一下fork()的返回值,如果成功,则在父进程中返回子进程的PID,并在子进程中返回0。如果失败,在父进程中返回-1,不创建子进程,并适当设置errno。
下面是运行的结果:
可以看到child正常打印,因为exit()会刷新缓存区,对于标准输出通常是使用行缓冲,意味着遇到换行符,刷新缓冲区,就会打印到屏幕上。
2._exit()
代码如下(示例):
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main()
{
pid_t pid = fork();
if(pid == -1){
perror("fork:");
exit(EXIT_FAILURE);
}else if(pid == 0){
printf("child"); //注意:后面没有换行符;
sleep(2);
_exit(EXIT_SUCCESS); //结束子进程;
}else{
printf("parent\n");
sleep(5);
printf("parent end\n");
}
return 0;
}
现在我们将子进程中的结束换成_exit(),来看一下打印的结果:
因为_exit()没有刷新缓存区的功能,所以printf()函数中的语句不会被打印到终端。
三.总结
exit() 与 _exit()的不同
- _exit()属于系统调用,能够使进程停止运行,并释放空间以及销毁内核中的各种数据结构。
- exit()基于_exit()函数实现,属于库函数, 会自动刷新I/O缓冲区