Linux创建进程必须fork么,Linux - fork() 创建进程

本文介绍了Linux下通过fork()函数创建进程的过程,详细阐述了父进程与子进程之间的内存副本关系,包括堆、栈、bss和data段的复制。在子进程中,局部变量、全局变量和指针的值可能不同,而文件描述符则共享,但其状态保持一致。同时,文章提到了Linux中COW(Copy-On-Write)机制,以提高效率。最后,通过示例展示了如何在代码中使用fork()创建进程并展示父子进程的不同行为。
摘要由CSDN通过智能技术生成

Linux - fork() 创建进程

Linux - fork() 创建进程

介绍创建进程之前,先简单地介绍一下 Linux 下的进程内存布局。

Stack - 所有函数的 local variables, arguments 和 return address 的存放内存区域

Heap - 动态申请的内存区域

bss - 所有未被初始化的 global variables 和 static variables 的存放内存区域

data - 所有已被初始化的 global variables 和 static variables 的存放内存区域

ee06f8d86f2a889afe8afac6267133c8.png

在 Linux 系统下可以通过调用 fork() 来创建一个新的进程。调用进程为父进程 (parent process) ,而诞生的新进程为子进程 (child process)。

fork() 比较特别,因为它会返回两次,也就是说会有两个返回值。我们可以通过这两个返回值来区分父、子进程。在父进程中,fock() 将会返回子进程的 process ID,而在子进程中成功返回0,失败则返回-1 (失败原因可参考手册)。子进程可以调用 getpid() 获取进程ID。

子进程诞生后将会获得来自父进程的数据副本,其中包括 bss, data segment 和 stack segment。值得注意的是,CentOS 8 无法保证调用 fork() 之后父、子进程的执行顺序。

我们可以从输出结果得知两个进程各自的数据都是独立的。

int main()

{

auto local_value = 66; // stored in stack segment

double* dPtr = new double(3.14);

switch (fork())

{

case - 1:

std::cout << "failed to fork.\n";

_exit(-1);

case 0:

*dPtr = 5.12;

std::cout << "child process ID: " << getpid() << "\n";

std::cout << "global value: " << (++global_value) << "\n";

std::cout << "local value: " << (++local_value) << "\n";

std::cout << "double pointer value: " << (*dPtr) << "\n";

std::cout << "----------------------------------\n";

_exit(0);

}

std::cout << "parent process ID: " << getpid() << "\n";

std::cout << "global value: " << global_value << "\n";

std::cout << "local value: " << local_value << "\n";

std::cout << "double pointer value: " << (*dPtr) << "\n";

std::cout << "----------------------------------\n";

exit(0);

}

输出结果:

[[email protected] Documents]$ ./exe

parent process ID: 3961

global value: 11

local value: 66

double pointer value: 3.14

----------------------------------

child process ID: 3962

global value: 12

local value: 67

double pointer value: 5.12

----------------------------------

[[email protected] Documents]$ ./exe

parent process ID: 3988

global value: 11

local value: 66

double pointer value: 3.14

----------------------------------

child process ID: 3989

global value: 12

local value: 67

double pointer value: 5.12

----------------------------------

执行 fork() 时,子进程将会获得来自父进程的文件描述符副本。和拷贝数据一样,尽管文件描述符也是副本,但本质上这些文件描述符都是指向内核维护 open file table。所以这些文件描述对应的文件的偏移量以及文件状态标志都是相同的。

dcaabf07b7cb11acfd72deb9d2e78373.png

#include

#include

#include

int main()

{

auto fd = open("/home/usr1/Documents/reading.txt", O_NONBLOCK);

switch (fork())

{

case - 1:

std::cout << "failed to fork.\n";

_exit(-1);

case 0:

auto flags = fcntl(fd, F_GETFL);

if (O_NONBLOCK & flags)

std::cout << "O_NONBLOCK flag is on\n";

_exit(0);

}

auto flags = fcntl(fd, F_GETFL);

if (O_NONBLOCK & flags)

std::cout << "O_NONBLOCK flag is on\n";

close(fd);

return 0;

}

输出结果:

O_NONBLOCK flag is on

O_NONBLOCK flag is on

由于子进程可能在诞生后就立刻执行 exec() 族函数。这意味子进程从父进程那里拷贝而来的数据全部都会被冲洗掉,那么拷贝的功夫就全部白费了。出于效率的考虑,COW 被投入使用。原理很简单,调用 fork() 后父、子进程共享 read only memory images。如果没有任一进程对这块内存映像进行修改,那么它们拥有的内存影响都属于同一份。如果有任何一个进程想要对数据进行修改,那么内核才会为该进程拷贝新的一份内存映像便于该进程独立使用。

Linux - fork() 创建进程相关教程

linux内核协议栈 netfilter 之 ip 层的table、rule、match、targ

linux内核协议栈 netfilter 之 ip 层的table、rule、match、target结构分析 在使用iptables过程中,经常会提到table、rule、match和target,这些在内核都有对应的数据结构(rule并没有对应结构体),在理解内核的逻辑代码之前,非常有必要先熟悉这些数据结构

ELK-详细设计

ELK-详细设计 1. 文档信息 创建者:汪彪 创建日期:2020-9-29 当前版本:01.00.00 版本 修改日期 修改人 修改说明 01.00.000 2020-09-29 汪彪 文档创建 2. ELK概述 ELK是ElasticSearch、Logstash和Kiabana的简称,这三者是核心套件,但并非全部。1:Elasticse

Linux命令学习笔记

Linux命令学习笔记 最近用到了一些Linux的命令,于是就有了这篇文档。 这是一个Linux常用命令的链接 https://segmentfault.com/a/1190000021950993 1. 特别注意:在Linux中引用目录等使用正斜杠“/”,在Windows中使用反斜杠“\” ,Linux中后缀没有那么重要

Unity3D中创建编辑器

Unity3D中创建编辑器 编辑器是开发工作中一个常用的功能,策划有时候会实时调整游戏数据或者创建关卡之类,就需要程序人员为其创建一个可编辑的编辑器。 U3D中为我们提供了可开发的面板,主要使用的是Editor模式下的OnGUI功能。测试代码如下: using System.C

nodejs创建图书管理系统

nodejs创建图书管理系统 图书管理系统实现增删改查 在json文件中实现 创建主入口文件index.js 路由分配层 业务逻辑层 相关文件 连接数据库实现 修改业务逻辑层 在json文件中实现 (1) 使用json 使用三层架构 去写 第一层: index.js 第二层: router.js 路由封装

Linux实验五:Linux环境下的C语言编程

Linux实验五:Linux环境下的C语言编程 文章目录 一、实验目的: 二、实验要求 三、实验内容 1、编写一段C语言程序使其完成:父进程创建两个子进程,每个进程都在屏幕上显示自己的进程ID号。 2、上机调试下面的程序,观察运行结果,分析原因。 3、利用两个管道

Linux系列之CentOS 7--笔记2:基本的命令的使用(1)

Linux系列之CentOS 7--笔记2:基本的命令的使用(1) 本笔记基于“狂神说Linux”强烈推荐看下视频,有助于理解Linux,但这些也仅仅是入门,根据自己的需求来吧。 目录 目录管理 绝对路径、相对路径 处理目录的常用命令 ls (列出目录) cd (切换目录) pwd ( 显

Java 顺序表-创建、有序表插入

Java 顺序表-创建、有序表插入 设计能存储int型元素的顺序表类SeqList。要求: 顺序表的最大容量在创建顺序表对象时指定; 实现从尾部追加(输入一组数,以-1结束)、打印顺序表的所有元素、插入元素至指定位置等基本操作。 实现向升序表中插入元素x,插入后

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值