目录
fork() 与 vfock() 都是创建一个进程,那它们有什么区别呢?
为什么vfork()子进程中可以调用_exit(),却不可以调用exit(),也不可以直接return呢?
fork函数
fork的使用
头文件 #include<unistd.h>
函数原型 pid_t fork(void)
fork功能 创建子进程 父子进程代码共享,数据个自开辟空间,私有一份(采用写时拷贝)
结果 一次调用 有两个返回值,它可能有三种不同的情况
1. 在父进程中,fork返回新创建的子进程的PID。父进程可以创建多个子进程.根据子进程的pid来区分子进程
2. 在子进程中,fork返回0;
3. 如果出现错误,fork返回一个负值。
一般来说,fork之后父、子进程执行顺序是不确定的,这取决于内核调度算法。进程之间实现同步需要进行进程通信。
一个父进程希望子进程同时执行不同的代码段,这在网络服务器中常见——父进程等待客户端的服务请求,当请求到达时,父进程调用fork,使子进程处理此请求。
一个进程要执行一个不同的程序,一般fork之后立即调用exec
进程调用fork,在内核中,进行以下操作:
- 分配新的内存块和内核数据给子进程
- 将父进程部分数据结构内容拷贝至子进程
- 添加子进程到系统进程列表中
- fork返回,进行调度器调度
fork出错可能有两种原因:
1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
2)系统内存不足,这时errno的值被设置为ENOMEM。
vfork函数
#include<sys/types.h>
#include<unistd.h>
pid_t vfork(void)
功能:创建子进程
成功:子进程中返回 0,父进程中返回子进程 ID。pid_t,为无符号整型。失败:返回 -1。
fork() 与 vfock() 都是创建一个进程,那它们有什么区别呢?
1)fork(): 父子进程的执行次序不确定。
vfork():保证子进程先运行,在它调用 exec(进程替换) 或 exit(退出进程)之后父进程才可能被调度运行。
2)fork(): 子进程拷贝父进程的地址空间,子进程是父进程的一个复制品。
vfork():子进程共享父进程的地址空间(准确来说,在调用 exec(进程替换) 或 exit(退出进程) 之前与父进程数据是共享的)子进程不会完全复制父进程的地址空间,它会在父进程的地址空间中运行。vfork创建的子进程,共享的是父进程当前栈帧的地址空间。
进程的正常终止方法?
- 调用_exit()
_exit()调用之后会立即进入内核
- 调用exit()
清理I/O缓冲区,关闭文件描述符后再退出进程
- 直接return
语言级别的,它表示了调用堆栈的返回,
如果是在主函数main, 自然也就结束当前进程
进程的异常终止
- ctrl + C
为什么vfork()子进程中可以调用_exit(),却不可以调用exit(),也不可以直接return呢?
exit()是对_exit()的封装,它自己在调用_exit()前会做很多清理工作,其中包括刷新并关闭当前进程使用的流缓冲(比如stdio.h里面的printf等),由于vfork()的子进程完全共享了父进程地址空间,子进程里面的流也是共享的父进程的流,所以子进程里面是不能做这些事的。
直接return就更不行,子进程return以后,会从当前函数的外部调用点后面继续执行,这后面子进程可能将会执行很多语句,结果就没法预料了。