浅析fork()和底层实现
记得以前初次接触fork()函数的时候,一直被“printf”输出多少次的问题弄得比较晕乎。不过,“黄天不负留心人"。哈~ 终于在学习进程和进程创建fork相关知识后,总算是大致摸清了其中的来龙去脉。废话不多讲,下面来谈谈本人的一点小小积累
- #include<unistd.h>
- pid_t fork(void);
- 返回值:自进程中返回0,父进程返回进程id,出错返回-1
fork()系统调用会通过复制一个现有进程来创建一个全新的进程. 进程被存放在一个叫做任务队列的双向循环链表当中.链表当中的每一项都是类型为task_struct成为进程描述符的结构.也就是我们写过的进程PCB.
fork()运行时做的事情
/*************************************************************************
2 > File Name: 1.c
3 > Author: tp
4 > Mail:
5 > Created Time: Mon 07 May 2018 07:57:28 PM CST
6 ************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main( void)
{
printf("change world!\n");
pid_t pid = fork();
if( pid == -) {perror("fork"),exit(); } printf( "pid=%d, returnVal=%d\n", getpid(), pid);
sleep( );
exit();
}
~
这段代码的运行结果,大家如果像我当时不了解fork的时候,一定会以为输出结果是两个"change world!",然后2个printf里面的内容. 因为


父子进程文件共享问题
/*************************************************************************
2 > File Name: 2.c
3 > Author: tp
4 > Mail:
5 > Created Time: Mon 07 May 2018 12:40:39 PM CST
6 ************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h> int set = ;
int main( void)
{
printf( "before fork\n");
pid_t pid = fork( );
if( pid < ){ perror(" fork"),exit( );} if( pid == )
{
++set;
printf( "son pid=%d, %d\n", getpid(), set);
}
else
{
sleep( );
printf( "parent pid=%d , %d\n", getpid( ), set);
}
exit( );
}
看一下结果:

不难注意到 “before fork”这句话只是被打印了一次,这个从上面的例子,这不难理解;与此同时子进程中的set的值被改变了。此时再进行一个重定向操作会发生什么
出现很神奇的现象! 这个时候打印了出了两次“before fork”,不仅仅是如此,上述针对父进程的标准输出执行重定向操作还导致了子进程也执行重定向操作。
透过现象看本质,来细细分析一下。针对打印两次“before fork”,首先,先要知道标准IO库是是带缓冲的,而像printf这种直接输出到标准输出时,这个缓冲区是由换行符刷新的;而当执行了重定向操作,这里就是将标准输出重定向到文件,文件就不会立即去刷新缓冲区(全缓冲的方式);好,由于在fork之前调用了一次printf,但fork之后,该行数据仍存留在缓冲区中,然后父进程数据空间被复制到子进程中,该行数据去也被复制了过去,这样父子进程都各自带有该行内容的缓冲区了,相当于子进程缓冲区添加了一行“before fork”,然后在每个进程exit之后,每个缓冲区的内容就被写到了相应的文件中。
再一个就是,在重定向父进程的标准输出时,子进程标准输出也被重定向。这就源于父子进程会共享所有的打开文件。 因为fork的特性就是将父进程所有打开文件描述符复制到子进程中。当父进程的标准输出被重定向,子进程本是写到标准输出的时候,此时自然也改写到那个对应的地方;与此同时,在父进程等待子进程执行时,子进程被改写到文件show.out中,然后又更新了与父进程共享的该文件的偏移量;那么在子进程终止后,父进程也写到show.out中,同时其输出还会追加在子进程所写数据之后,这也就解释了上面为什么“before fork”会在一个文件中打印两次。
在fork之后处理文件描述符一般又以下两种情况:
1.父进程等待子进程完成。此种情况,父进程无需对其描述符作任何处理。当子进程终止后,它曾进行过读,写操作的任一共享描述符的文件偏移已发生改变。
2.父子进程各自执行不同的程序段。这样fork之后,父进程和子进程各自关闭它们不再使用的文件描述符,这样就避免干扰对方使用的文件描述符了。这类似于网络服务进程。
同时父子进程也是有区别的:它们不仅仅是两个返回值不同;它们各自的父进程也不同,父进程的父进程是ID不变的;还有子进程不继承父进程设置的文件锁,子进程未处理的信号集会设置为空集等不同
fork()函数在底层中做了什么?

vfork和fork的之间的比较:
vfork()的诞生是在fork()还没有写时拷贝的时候,因为那个时候创建一个子进程的成本太大了,如果一下子创建好多了那么程序的效率一定会下降. 然后就有人提出了vfork(). vfork的实现原理非常简单,就是子进程,父进程完全公用一个资源. 就是是有人修改了内容,甚至main()函数退出了也不会新开辟一个空间. 所以这里里会有问题的,如果你的一个子进程没有使用exit()退出,那么程序就会出现段错误. 不相信可以去试一试~
vfork和fork之间的区别:
浅析fork()和底层实现的更多相关文章
- Linux中fork()函数的底层实现【转】
转自:http://blog.csdn.net/duoru_xiong/article/details/76358812 1. fork(),vfork(),clone()的区别 这三个系统调用的底层 ...
- const浅析
前言 c++中使用到const的地方有很多, 而且const 本身也针对不同的类型可能有不同的含义, 比如对指针就有顶层和底层. 本节就是探讨关于C++中const的在不同的地方不同表现或含义. co ...
- Java基础教程——List(列表)
集合概述 Java中的集合,指一系列存储数据的接口和类,可以解决复杂的数据存储问题. 导包:import java.util.*; 简化的集合框架图如下: List·列表 ArrayList List ...
- windows消息钩子注册底层机制浅析
标 题: [原创]消息钩子注册浅析 作 者: RootSuLe 时 间: 2011-06-18,23:10:34 链 接: http://bbs.pediy.com/showthread.php?t= ...
- 从底层源码浅析Mybatis的SqlSessionFactory初始化过程
目录 搭建源码环境 POM依赖 测试SQL Mybatis全局配置文件 UserMapper接口 UserMapper配置 User实体 Main方法 快速进入Debug跟踪 源码分析准备 源码分析 ...
- 关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析
关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析 如下代码,当我们在使用 ReentrantLock 进行加锁和解锁时,底层到底是如何帮助我们进行控制的啦 ...
- iOS 底层框架的浅析
1.简介 IOS是由苹果公司为iPhone.iPod touch和iPad等设备开发的操作系统. 2.知识点 iPhone OS(现在叫iOS)是iPhone, iPod touch 和 iPad 设 ...
- linux fork函数浅析
#include <sys/types.h> #include <unistd.h> /* 功能:复制进程 參数:无 返回值: 成功: 父进程:返回子进程id 子进程:返回0 ...
- 浅析linux中的fork、vfork和clone
各种大神的混合,做个笔记. http://blog.sina.com.cn/s/blog_7598036901019fcg.html http://blog.csdn.net/kennyrose/ar ...
随机推荐
- AnimatedPathView实现自定义图片标签
老早用过小红书app,对于他们客户端笔记这块的设计非常喜欢,恰好去年在小红书的竞争对手公司,公司基于产品的考虑和产品的发展,也需要将app社交化,于是在社区分享这块多多少少参照了小红书的设计,这里面就 ...
- 【Android 应用开发】 FastJson 使用详解
博客地址 :http://blog.csdn.net/shulianghan/article/details/41011605 fastjson 源码地址 : -- GitHub : https:// ...
- 怎样写一个与Windows10 IE11兼容的标准BHO?
p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; f ...
- C++ 仿函数/函数指针/闭包lambda
在上一篇文章中介绍了C++11新引入的lambda表达式(C++支持闭包的实现),现在我们看一下lambda的出现对于我们编程习惯的影响,毕竟,C++11历经10年磨砺,出140新feature,对于 ...
- 高德地图SDK使用经验
下文说的是高德地图 Android SDK版本,详细版本如下: 2D地图:v2.3.1 定位:v1.3.0 导航:v1.1.1 发现的问题如下,其中一些疑是地图BUG,一些是需要你自己小心的地方: 1 ...
- MFC中使用SDL播放音频没有声音的解决方法
本文所说的音频是指的纯音频,不包含视频的那种. 在控制台中使用SDL播放音频,一般情况下不会有问题. 但是在MFC中使用SDL播放音频的时候,会出现没有声音的情况.经过长时间探索,没有找到特别好的解决 ...
- 【一天一道LeetCode】#15 3Sum
一天一道LeetCode系列 (一)题目 Given an array S of n integers, are there elements a, b, c in S such that a + b ...
- cocos2d-x 游戏开发之有限状态机(FSM) (四)
cocos2d-x 游戏开发之有限状态机(FSM) (四) 虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作.SMC(http://smc.sourceforge ...
- redis简介(keeper实时报表的基本部分)
网上有一篇介绍Redis的文章,由浅入深地讲解了Redis:http://blog.mjrusso.com/2010/10/17/redis-from-the-ground-up.html.强烈建议对 ...
- Oracle E-Business Suite Maintenance Guide Release 12.2(Patching Procedures)
更多内容参考: http://docs.oracle.com/cd/E51111_01/current/acrobat/122ebsmt.zip Preparing for Patching For ...
