linux多进/线程编程(2)—— fork函数和进程间“共享”数据
参考:
1.博客1:https://www.pianshen.com/article/4305691855/
fork:在原进程的基础上“分叉”出一个子进程,即创建一个子进程。
NAME
fork - create a child process SYNOPSIS
#include <unistd.h> pid_t fork(void); DESCRIPTION
fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process.
返回值:
RETURN VALUE
On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set
appropriately.
示例代码1,基本使用:
pid_t pid = fork();
if (pid == 0) {
printf("child, pid=%d, ppid=%d\n", getpid(), getppid());
sleep(2);
printf("child, i will die, pid=%d, ppid=%d\n", getpid(), getppid());
} else if (pid > 0) {
while (true) {
printf("parent, child_pid=%d, self_pid=%d, father_pid=%d\n", pid, getpid(), getppid());
sleep(1);
}
}
示例代码2,创建多个子进程:
pid_t pid { 0 };
int i { 0 };
for (i = 0; i < 5; ++i) {
pid = fork();
if (pid == 0) {
//son
printf("i=%d, child, pid=%d, ppid=%d\n", i, getpid(), getppid());
break;
} else if (pid > 0) {
//father
//printf("parent, child_pid=%d, self_pid=%d, father_pid=%d\n", pid, getpid(), getppid());
} else {
perror("error\n");
exit(1);
}
}
sleep(i+1);//process sleep
if (i < 5) {
printf("i=%d, child will exit, pid=%d, ppid=%d\n", i, getpid(), getppid());
} else {
printf("parent will exit, child_pid=%d, self_pid=%d, father_pid=%d\n", pid, getpid(), getppid());
}
进程间共享哪些内容?
通过fork函数建立的子进程时:
1、父子进程之间在刚fork后,刚刚创建子进程后:
(这个时候是完全一样的,但是并不代表后面就可以共享,进程间共享是后续的内容:管道,信号,队列,共享内存等,因为进程间的数据是读时共享,写时复制的)
(1)父子相同处: 全局变量、.data、.bbs、.text、栈、堆、环境变量、用户ID、宿主目录(进程用户家目录)、进程工作目录、信号处理方式等等,即0~3G的用户空间是完全一样的。
(2)父子不同处: 1.进程ID 2.fork返回值 3.父进程ID 4.进程运行时间 5.闹钟(定时器) 6.未决信号集
2、似乎,子进程复制了父进程0-3G用户空间内容,以及父进程的PCB(内核模块在物理内存只有一份),但pid等不同。真的每fork一个子进程都要将父进程的0-3G地址空间完全拷贝一份,然后在映射至物理内存吗?
当然不是,父子进程间遵循读时共享写时复制的原则。这样设计,无论子进程执行父进程的逻辑还是执行自己的逻辑都能节省内存开销。具体见下图1和图2解释。
读时共享写时复制这一机制是由MMU(内存管理单元)来实现的。
注意:只有进程空间的各段的内容要发生变化时(子进程或父进程进行写操作时,都会引起复制),才会将父进程的内容复制一份给子进程。在fork之后两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。即父子进程在逻辑上仍然是严格相互独立的两个进程,各自维护各自的参数,只是在物理上实现了读时共享,写时复制。
(1)fork函数创建子进程后,见图1,内核只为新生成的子进程创建虚拟空间结构,它们来复制于父进程的虚拟空间结构,但是不为这些段分配物理内存,它们共享父进程的物理空间,

(2)如下图2,直到父子进程中有更改相应段(用户空间中)的行为发生时,再为子进程相应的段分配物理空间。

3、父子进程一直共享: 1. 文件描述符(打开文件的结构体) ,注意不是共享文件描述符本身这个整形数,而是共享同一个文件对应的FILE *结构体指针,其实一个文件打开后只能有一个FILE结构体,因此对于多有的进程都是共享这一个结构体,不仅仅只是父子进程。 2. mmap建立的映射区 (进程间通信详解)。 —》共享内存区是进程间通信的一种方式。
特别的,fork之后父进程先执行还是子进程先执行不确定。取决于内核所使用的调度算法。
linux多进/线程编程(2)—— fork函数和进程间“共享”数据的更多相关文章
- linux多进/线程编程(7)——多线程1(线程的创建,回收,分离,设置线程属性等)
参考资料: 1.博客1:https://blog.csdn.net/zhou1021jian/article/details/71531699 2.博客2:https://blog.csdn.net/ ...
- linux多进/线程编程(4)——进程间通信之pipe和fifo
前言: Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间.任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块 ...
- linux多进/线程编程(3)——wait、waitpid函数和孤儿、僵尸进程
当使用fork创建多个进程后,需要解决子进程回收的问题.wait和waitpid函数就是做这个工作的. 假设子进程没有合理的回收,可能会带来两个问题: 1.孤儿进程(父进程挂了,子进程活着),孤儿进程 ...
- linux多进/线程编程(5)——进程间通信之mmap
参考资料: 1.博客1:https://www.jianshu.com/p/755338d11865 mmap:一种内存映射文件的方法 memory map 父子进程和无亲缘关系的进程,都可以将自身用 ...
- linux多进/线程编程(1)—— 基础概念(PCB、MMU、进程状态)
学习大概就是不断迭代.重构的过程,不复习的学习是不负责任的,亦是无用的. 本系列博客主要作为个人记录,主要是贴图和代码,不做详细解释,以后有时间可能会重写:从下一篇开始上代码,代码可以运行是对自己的最 ...
- windows核心编程之进程间共享数据
有时候我们会遇到window进程间共享数据的需求,例如说我想知道系统当前有多少某个进程的实例. 我们能够在程序中定义一个全局变量.初始化为0.每当程序启动后就加1.当然我们我们能够借助第三方介质来储存 ...
- Linux下C语言编程实现spwd函数
Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...
- 关于fork( )函数父子进程返回值的问题
fork()是linux的系统调用函数sys_fork()的提供给用户的接口函数,fork()函数会实现对中断int 0x80的调用过程并把调用结果返回给用户程序. fork()的函数定义是在init ...
- 【Linux 进程】fork父子进程间共享数据分析
之前我们通过fork()函数,得知了父子进程之间的存在着代码的拷贝,且父子进程都相互独立执行,那么父子进程是否共享同一段数据,即是否存在着数据共享.接下来我们就来分析分析父子进程是否存在着数据共享. ...
随机推荐
- 学习JAVAWEB第一天
第一天:单元测试(junit)黑盒测试:不需要写代码,给输入值,看程序能否给出期望值白盒测试:需要写代码,关注程序的具体执行流程junit使用步骤:步骤1:定义一个测试类建议类名,被测试类名后面加一个 ...
- C++ 微信多开
应用是如何判断多开 一.通过查找窗口标题或者类名来判断程序是否正在运行. 二.通过互斥对象确定程序是否运行,大多数软件都是使用CreateMutexW 判断多开的. 三.内存映射物理文件,控制多开. ...
- C++ STL:std::unorderd_map 物理结构详解
拉链法的 unordered_map 和你想象中的不一样 根据数组+拉链法的描述,我们很快能想到下面这样的拉链法实现的哈希表,但真的是这样吗?一起看下源码里的实现是怎么样的. 深入STL源码 代码不会 ...
- Python 单元测试 实战演练
结合实例,联系单元测试. 文件结构: |----Python_unittest |--------math_operation.py # 定义了类[class MathOperation:],类里面定 ...
- 论文解读(GAN)《Generative Adversarial Networks》
Paper Information Title:<Generative Adversarial Networks>Authors:Ian J. Goodfellow, Jean Pouge ...
- 生成"cmd.exe"错误
转载请注明来源:https://www.cnblogs.com/hookjc/ 在VC2005里打开"工具"菜单,选择"选项",打开"选项" ...
- Docker的数据管理(下)——docke镜像的创建
Docker的数据管理(下)--docke镜像的创建 1.基于现有镜像创建 2.基于本地模板创建 3.基于 dockerfile 创建 4.Dockerfile 镜像操作常用命令 5.dockerfi ...
- python——虚拟环境管理大合集
个人常用:pipenv 安装 pip3 install pipenv 创建虚拟环境 # 默认安装在~/.local/virtualenv下 mkdir project cd project pipen ...
- 关于一些基础的dp——硬币的那些事(dp的基本引入)
1.最少硬币问题大体题意: 有n种硬币,面值分别是v1,v2......vn,数量无限,输入一个非负整数s,选用硬币使其和为s,要求输出最少的硬币组合. 我们可以这样分析: 定义一个名为Min[s]的 ...
- Elasticsearch笔记2
1 搜索所有文档中还有某个字段的方法: localhost:9200/get-together/group/_search?pretty { "query": { "qu ...