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()函数,得知了父子进程之间的存在着代码的拷贝,且父子进程都相互独立执行,那么父子进程是否共享同一段数据,即是否存在着数据共享.接下来我们就来分析分析父子进程是否存在着数据共享. ...
随机推荐
- linux用户密码过期导致命令执行失败
背景介绍: 使用zabbix调用系统命令,检查时间同步,发现一直在报错,root 用户执行无异常,问题还是出现zabbix用户上面. [zabbix@test-10-12 ~]$ sudo ntpda ...
- pytorch运行错误:ValueError: too many dimensions 'str'
问题: 本人在使用BERT进行微调的时候,在读取数据的时候出现了一个错误:ValueError: too many dimensions 'str' 于是我Debug了以后,发现问题出现在这个部 ...
- ajaxl利用json 传送数据的 三种提交方式?
一.在servlet类中添加几个javabean对象,放置数据. package com.aaa.servlet; import java.io.IOException; import java.ut ...
- 最近公共祖先-LCA
题目描述 时间限制:1.2s 内存限制:256.0MB 问题描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入格式 第一行包含三个正整数\(N\),\(M\),\(S\),分别 ...
- oeasy教您玩转python - 006 - # hello world
Hello World! 回忆上次内容 python3 的程序是一个 5.3M 的可执行文件 python3 里面全都是 cpu 指令 可以执行的那种指令 我们可以把指令对应的汇编找到 objdu ...
- Java中class的前面添加public和不添加public有什么区别?
需要知道的是修饰类和变量的用来控制这个被修饰的类和变量的适用范围的修饰词有: 1.public:表示公开的类和变量,既所有的类都可以引入使用的. 2.protected:表示受保护的类,只有子孙类和本 ...
- cookie、session、jsession 关系
感谢大佬:https://www.cnblogs.com/fsjin/articles/3490531.html 在使用CAS的时候,对Cookies.session.jsession 这三者是什么不 ...
- WordPress子模板继承
很多时候我们不想重写模板,而是想在某个模板的基础上进行修改,那么这个时候我们就需要用到模板继承技巧. 子主题开发 style.css 是必须的文件,只需要新增 Template: 父模板的文件夹名
- iOS App 架构文章推荐
iOS应用开发架构 iOS应用架构谈系列 阿里技术沙龙 2.2.1. Hybrid App 2.2.2. taobao 客户端架构 2.2.3. alipay 客户端架构 iOS APP 架构漫谈 ...
- jdk1.5新特性之------->可变参数
/* jdk1.5新特性之------->可变参数 需求: 定义一个函数做加法功能(函数做几个数据 的加法功能是不确定). 可变参数的格式: 数据类型... 变量名 可变参数要 注意的细节: 1 ...