POST
Linux fork() 函数
本文主要总结了Linux fork()
函数的使用。
在Linux中每个进程拥有独立的地址空间,地址空间包括代码段、数据段和堆栈段。
代码段:存储程序的代码
数据段:存储程序的全局变量和动态分配的内存
堆栈段:存储函数运行时的局部变量
进程之间的地址空间是隔离的。
fork()
函数的作用是新建立一个进程。这个进程是从父进程COPY过来,因此和父进程几乎完全相同。
fork()
函数的原型如下,需要注意的是函数的返回值。
函数返回值:
注意,fork被调用后,是要返回两次,也就是有两个返回值, 分别代表了父进程和子进程,这点和一般的函数调用不同。
看代码。
执行结果如下。
我们可以看到相同的代码段被执行了两次。这是因为调用fork()
函数后,就变成两个进程在执行了,这两个进程的执行逻辑完全相同,在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。如果把代码稍作修改。
结果如下,可以看出到是子进程先执行,父进程后执行,与程序的执行顺序无关。
关于fork()
函数的执行原理,用到了“写时复制”的技术,参考以下的博文,讲的比较清楚。
https://www.cnblogs.com/zhangchaoyang/articles/2317420.html
fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑, linux中引入了“写时复制“技术,也就是只有进程空间的各段的内容要发生变化时,才会将父进程的内容 复制一份给子进程。在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、 数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。 当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间,如果不是因为exec,内核会 给子进程的数据段、堆栈段分配相应的物理空间(至此两者有各自的进程空间,互不影响),而代码段继续共 享父进程的物理空间(两者的代码完全相同)。而如果是因为exec,由于两者执行的代码不同,子进程的代码 段也会分配单独的物理空间。 fork之后内核会通过将子进程放在队列的前面,以让子进程先执行,以免父进程执行导致写时复制,而后子进程执 行exec系统调用,因无意义的复制而造成效率的下降。 fork时子进程获得父进程数据空间、堆和栈的复制,所以变量的地址(当然是虚拟地址)也是一样的。
参考:
https://www.cnblogs.com/zhangchaoyang/articles/2317420.html
https://blog.csdn.net/zhangxiao93/article/details/72811700