引言
在linux下,进行多进程相关编程的时候,会使用到fork系列函数。其中fork()
和vfork()
存在哪些区别?
exit()
可以终止调用进程,不执行exit()
后的代码,那 _exit()
与 exit()
的区别在哪里?为什么建议在fork出的子进程中使用_exit()
退出,而非使用exit()
退出?
fork 与 vfork
fork
- 调用方法
1 | #include <sys/types.h> |
正确返回:在父进程中返回子进程的进程号,在子进程中返回0
错误返回:-1
子进程是父进程的一个拷贝。即,子进程从父进程得到了数据段和堆栈段的拷贝,这些需要分配新的内存;而对于只读的代码段,通常使用共享内存的方式访问。fork返回后,子进程和父进程都从调用fork函数返回处开始执行。
父进程与子进程的不同之处在于:fork的返回值不同——父进程中的返回值为子进程的进程号,而子进程为0
fork函数调用的用途
⑴ 一个进程希望复制自身,从而父子进程能同时执行不同段的代码。
⑵ 进程想执行另外一个程序
vfork
- 调用方法
1
2
3
4#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
正确返回:在父进程中返回子进程的进程号,在子进程中返回0
错误返回:-1
vfork函数调用的用途
用
vfork
创建的进程主要目的是用exec
系列函数执行另外的程序,与fork
的第二个用途相同
fork与vfork的区别
- `fork`要拷贝父进程的数据段;而`vfork`则不需要完全拷贝父进程的数据段,在子进程没有调用`exec`或`_exit`之前,子进程与父进程共享数据段。
- `fork`不对父子进程的执行次序进行任何限制;而在`vfork`调用中,父进程挂起,直到子进程调用了`exec`系列函数或`_exit`函数,之后两者各自执行。需要注意,子进程不应该`return`或者调用`exit()`。
exit与_exit
exit()
和_exit()
之间的基本区别在于前者执行与用户模式构造相关的清理库,并调用用户提供的清理函数,而后者仅执行进程的内核清理。更加具体的:
1 | exit(3) - Linux man page |
1 | exit(2) - Linux man page |
可知:
_exit()
和exit()
都会执行的事情: close文件描述符;终止进程;_exit()
不会执行,但exit()
会执行的的事情: 调用所有atexit(3)
和on_exit(3)
中注册的函数; flush 并 close 所有stdio
流; 移除由tmpfile()
创建的文件;exit()
是c库函数,所以是在man(3)
, 而_exit()
是系统函数,是在man(2)
中。1
2
3
4
5
6
7
8
9
10
11
12
13
14MANUAL SECTIONS
The standard sections of the manual include:
1 User Commands
2 System Calls
3 C Library Functions
4 Devices and Special Files
5 File Formats and Conventions
6 Games et. al.
7 Miscellanea
8 System Administration tools and Daemons
Distributions customize the manual section to their specifics,
which often include additional sections.
不当使用exit()
可能造成的问题:
- io buffer 被flush 两次,是的输出内容异常,例如:在fork 之后,子进程中调用
exec
系列函数执行相应的操作,但exec
函数调用失败,于是调用exit()
退出子进程,此时,会对stdio流进行flush操作,由于子进程中stdout、stderr复制自父进程,如果此时有缓冲,就会将其输出,从而造成两次输出同一缓冲内容,得到异常的输出。 - 可能会意外移除由
tmpfile()
创建的缓冲文件。 - 在c++中可能会错误地运行静态对象的析构函数。
- 当使用
vfork
时,错误调用exit()
会对父进程的数据状态造成影响。
注意:
- 在绝大多数情况下适用的基本规则是:对于每个main(),
exit()
只应该被调用一次。
参考链接
- linux fork函数与vfork函数,exit,_exit区别
- Why use _exit rather than exit in the child branch of a fork?
- What is the difference between using _exit() & exit() in a conventional Linux fork-exec?
- Why should a child of a vfork or fork call _exit() instead of exit()?
- exit() vs _Exit() in C and C++
- fork(2) - Linux man page
- vfork(2) - Linux man page
- clone(2) - Linux man page
- exit(3) - Linux man page
- exit(2) - Linux man page
- What do the numbers in a man page mean?