fork入门知识

系统调用fork用于创建一个新进程,称为子进程,它与进程(称为系统调用fork的进程)同时运行,此进程称为父进程。创建新的子进程后,两个进程将执行fork()系统调用之后的下一条指令。子进程使用相同的pc(程序计数器),相同的CPU寄存器,在父进程中使用的相同打开文件。

同时,fork()函数也可以通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事(比如开启2个qq),但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
  一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

/* *  fork_test.c *  version 1 *  Created on: 2010-5-29 *      Author: wangth */
#include <unistd.h>
#include <stdio.h>
int main ()
{   pid_t fpid; //fpid表示fork函数返回的值int count=0;fpid=fork();if (fpid < 0)printf("error in fork!");else if (fpid == 0) {printf("i am the child process, my process id is %d\n",getpid());printf("我是子进程\n");//对某些人来说中文看着更直白。count++;}else {printf("i am the parent process, my process id is %d\n",getpid());printf("我是父进程\n");count++;}printf("统计结果是: %d\n",count);  return 0;
}

运行结果是:

i am the parent process, my process id is 75391
我是父进程
统计结果是: 1
i am the child process, my process id is 75393
我是子进程
统计结果是: 1

在语句fpid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的几乎完全相同,将要执行的下一条语句都是if(fpid<0)……
  为什么两个进程的fpid不同呢,这与fork函数的特性有关。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
  1)在父进程中,fork返回新创建子进程的进程ID;
  2)在子进程中,fork返回0;
 3)如果出现错误,fork返回一个负值;

在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

引用一位网友的话来解释fpid的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其fpid为0.
   fork出错可能有两种原因:
  1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
  2)系统内存不足,这时errno的值被设置为ENOMEM。
  创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
  每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。
   fork执行完毕后,出现两个进程,

  有人说两个进程的内容完全一样啊,怎么打印的结果不一样啊,那是因为判断条件的原因,上面列举的只是进程的代码和指令,还有变量啊。
  执行完fork后,进程1的变量为count=0,fpid!=0(父进程)。进程2的变量为count=0,fpid=0(子进程),这两个进程的变量都是独立的,存在不同的地址中,不是共用的,这点要注意。可以说,我们就是通过fpid来识别和操作父子进程的。
  还有人可能疑惑为什么不是从#include处开始复制代码的,这是因为fork是把进程当前的情况拷贝一份,执行fork时,进程已经执行完了int count=0;fork只拷贝下一个要执行的代码到新的进程。 
fock简单的就说道这里 , 详情看 https://www.jianshu.com/p/484af1700176


mmap()入门

mmap将一个文件或者其它对象映射进内存。比如读取可执行文件,动态库
内存映射文件,是由一个文件到一块内存的映射。系统提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping)。通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。mmap并不分配空间, 只是将文件映射到调用进程的地址空间里(但是会占掉你的 virutal memory), 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后,内存中的内容并不会立即更新到文件中,而是有一段时间的延迟,你可以调用msync()来显式同步一下, 这样你所写的内容就能立即保存到文件里了.这点应该和驱动相关。如下图所示:

由上图可以看出,进程的虚拟地址空间,由多个虚拟内存区域构成。虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址范围。上图中所示的text数据段(代码段)、初始数据段、BSS数据段、堆、栈和内存映射,都是一个独立的虚拟内存区域。而为内存映射服务的地址空间处在堆栈之间的空余部分。

mmap内存映射的实现过程,总的来说可以分为三个阶段:

(一)进程启动映射过程,并在虚拟地址空间中为映射创建虚拟映射区域

1、进程在用户空间调用库函数mmap,原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

2、在当前进程的虚拟地址空间中,寻找一段空闲的满足要求的连续的虚拟地址

3、为此虚拟区分配一个vm_area_struct结构,接着对这个结构的各个域进行了初始化

4、将新建的虚拟区结构(vm_area_struct)插入进程的虚拟地址区域链表或树中

(二)调用内核空间的系统调用函数mmap(不同于用户空间函数),实现文件物理地址和进程虚拟地址的一一映射关系

5、为映射分配了新的虚拟地址区域后,通过待映射的文件指针,在文件描述符表中找到对应的文件描述符,通过文件描述符,链接到内核“已打开文件集”中该文件的文件结构体(struct file),每个文件结构体维护着和这个已打开文件相关各项信息。

6、通过该文件的文件结构体,链接到file_operations模块,调用内核函数mmap,其原型为:int mmap(struct file *filp, struct vm_area_struct *vma),不同于用户空间库函数。

7、内核mmap函数通过虚拟文件系统inode模块定位到文件磁盘物理地址。

8、通过remap_pfn_range函数建立页表,即实现了文件地址和虚拟地址区域的映射关系。此时,这片虚拟地址并没有任何数据关联到主存中。

(三)进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝

注:前两个阶段仅在于创建虚拟区间并完成地址映射,但是并没有将任何文件数据的拷贝至主存。真正的文件读取是当进程发起读或写操作时。

9、进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不在物理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。

10、缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。

11、调页过程先在交换缓存空间(swap cache)中寻找需要访问的内存页,如果没有则调用nopage函数把所缺的页从磁盘装入到主存中。

12、之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址,也即完成了写入到文件的过程。

注:修改过的脏页面并不会立即更新回文件中,而是有一段时间的延迟,可以调用msync()来强制同步, 这样所写的内容就能立即保存到文件里了。

函数原型

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

返回说明

成功执行时,mmap()返回被映射区的指针。失败时,mmap()返回MAP_FAILED[其值为(void *)-1], error被设为以下的某个值:

EACCES:访问出错
EAGAIN:文件已被锁定,或者太多的内存已被锁定
EBADF:fd不是有效的文件描述词
EINVAL:一个或者多个参数无效
ENFILE:已达到系统对打开文件的限制
ENODEV:指定文件所在的文件系统不支持内存映射
ENOMEM:内存不足,或者进程已超出最大内存映射数量
EPERM:权能不足,操作不允许
ETXTBSY:已写的方式打开文件,同时指定MAP_DENYWRITE标志
SIGSEGV:试着向只读区写入
SIGBUS:试着访问不属于进程的内存区

参数

start:映射区的开始地址

length:映射区的长度

prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起

PROT_EXEC:页内容可以被执行

PROT_READ:页内容可以被读取

PROT_WRITE:页可以被写入

PROT_NONE:页不可访问

flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体

MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
MAP_DENYWRITE //这个标志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。
MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
MAP_FILE //兼容标志,被忽略。
MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。

fd:有效的文件描述词。如果MAP_ANONYMOUS被设定,为了兼容问题,其值应为-1

offset:被映射对象内容的起点

相关函数

int munmap( void * addr, size_t len )

成功执行时,munmap()返回0。失败时,munmap返回-1,error返回标志和mmap一致;

该调用在进程地址空间中解除一个映射关系,addr是调用mmap()时返回的地址,len是映射区的大小;

当映射关系解除后,对原来映射地址的访问将导致段错误发生。

int msync( void *addr, size_t len, int flags )

一般说来,进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执行该操作。

可以通过调用msync()实现磁盘上文件内容与共享内存区的内容一致。

1、使用mmap需要注意的一个关键点是,mmap映射区域大小必须是物理页大小(page_size)的整倍数(32位系统中通常是4k字节)。原因是,内存的最小粒度是页,而进程虚拟地址空间和内存的映射也是以页为单位。为了匹配内存的操作,mmap从磁盘到虚拟地址空间的映射也必须是页。

2、内核可以跟踪被内存映射的底层对象(文件)的大小,进程可以合法的访问在当前文件大小以内又在内存映射区以内的那些字节。也就是说,如果文件的大小一直在扩张,只要在映射区域范围内的数据,进程都可以合法得到,这和映射建立时文件的大小无关。具体情形参见“情形三”。

3、映射建立之后,即使文件关闭,映射依然存在。因为映射的是磁盘的地址,不是文件本身,和文件句柄无关。同时可用于进程间通信的有效地址空间不完全受限于被映射文件的大小,因为是按页映射。

其他详细可参考 : https://blog.csdn.net/bbzhaohui/article/details/81665370

操作系统的fock和mmap相关推荐

  1. 沪漂程序媛妹子的一天...

    Hey guys,这里是程序员cxuan,欢迎您收看我最新一期的文章.今天给大家带来的是上海女程序媛的一天. 原文链接:沪漂程序媛妹子的一天- 搬砖⽇记 基于客套是中国⼈的交流⽅式,所以,我也先寒暄⼀ ...

  2. 算法:倒排表/倒排索引(Inverted index)

    搜索引擎最核心的技术, 倒排索引技术,倒排索引可能需要分成几篇文章才说得完,我们先会说说倒排索引的技术原理,然后会讲讲怎么用一些数据结构和算法来实现一个倒排索引,然后会说一个 索引器怎么通过 文档来生 ...

  3. 讲一讲什么是 MMAP

    1. mmap 基础概念 mmap 即 memory map,也就是内存映射. mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一 ...

  4. LMDB中的mmap、Copy On Write、MVCC深入理解——讲得非常好,常来看看!

    LMDB基本架构 lmdb的基本架构如下:  lmdb的基本做法是使用mmap文件映射,不管这个文件存储实在内存上还是在持久存储上.lmdb的所有读取操作都是通过mmap将要访问的文件只读的映射到虚拟 ...

  5. linux存储--mmap与sendfile(十七)

    零拷贝这三个字,一直是服务器网络编程的关键字,任何性能优化都离不开.在 Java 程序员的世界,常用的零拷贝有 mmap 和 sendFile.那么,他们在 OS 里,到底是怎么样的一个的设计?本文将 ...

  6. OS - MMAP初探

    文章目录 生猛干货 What's mmap mmap 函数 mmap() 的底层原理 虚拟内存空间与物理内存空间 vm_area_struct 结构 对文件的读写 搞定计算机基础内功 生猛干货 计算机 ...

  7. 零拷贝、mmap、sendfile

    目录 零拷贝 mmap sendFile 总结 零拷贝 要了解零拷贝,首先得先了解一下传统 IO 的执行流程,这里举个例子,通过传统的 IO 进行网络传输来传输一个文件. 先上一张图,这张图就代表了传 ...

  8. Linux网络处理“零拷贝”技术mmap()内核进程间通信设计8086分页管理——摆在一起来谈谈...

    Jack:最近听说了网络处理的"零拷贝"技术,觉得非常神奇,在网上查阅了很多资料.不过,并不是太明白--知其然,而不知其所以然.你能通俗地解释一下吗? 我:这是一个相对比较复杂的话 ...

  9. 操作系统的中的 IO

    文章目录 IO 是什么 I/O模型 阻塞 IO 非阻塞 IO IO 多路复用 信号驱动式 IO 异步 IO 五种 IO 模型对比 IO 是什么 IO 全称为 Input/Output ,翻译过来就是 ...

最新文章

  1. 正式开课!如何学习相机模型与标定?(单目+双目+鱼眼+深度相机)
  2. 如何在node.js中发出HTTP POST请求?
  3. tiny4412 串口驱动分析九 --- shell终端
  4. Linux 安装 Elasticsearch-rtf
  5. Java动物类enjoy方法打印,面向对象编程题汇总
  6. Python程序开发——第一章 基本python语法
  7. javafx 自定义控件_JavaFX自定义控件– Nest Thermostat第2部分
  8. 传输层:IP 地址解析 路由转发
  9. php字符长度函数漏洞 ctf,CTF中常见php-MD5()函数漏洞
  10. android 清理工具,Android 版 Avira Optimizer 是 Android 手機清理工具
  11. mysql2005本地连接_sql2005连接配置详细图解
  12. 吴恩达CS 230深度学习课开学了!秋季视频全部上线,课件小抄应有尽有
  13. 动网论坛 php版,动网即将推出第二代PHP版本论坛系统
  14. 看完小区丰巢柜身上的字 我决定了
  15. 大数据Clouder专项技能认证课程:Quick BI企业报表制作
  16. 从A至Z,用30个单词来概括过去十年的游戏行业
  17. Java job interview:WinForm界面特效设计案例导航图分享
  18. 字符型数据与数值型数据之间的转换
  19. 家用电信光猫更换教程+设置路由模式
  20. 关于数字化转型方法论的一些思考

热门文章

  1. LCD / OLED显示汉字,取模软件PCtoLCD2002完美版
  2. python: 字符串转浮点数
  3. 葡萄牙晋级世界杯决赛
  4. web实验报告——JSP动态网页编程
  5. 分数求和的三种方法(1/1-1/2+1/3-1/4+1/5+...+1/n)
  6. 断言(assert)方法
  7. 科研伦理与学术规范 期末考试1(50题)
  8. 来了!CDEC2022全国六城首站——深圳!
  9. 对接IronSource广告(视频)
  10. 文本字段的html标签是什么,HTML常用标签及属性