《Linux系统编程篇》fork函数——基础篇

news2024/11/29 12:41:20

文章目录

  • 引言
  • fork() 函数概述
    • 父子进程
  • fork函数
    • fork() 的常见问题
    • fork() 的优势与限制
  • 结论

命为志存。 —— 朱熹

引言

《Linux系统编程篇》——基础篇首页传送门

本节我们正式进入Linux的进程代码编写。

fork() 是 Unix 系统中一个重要的系统调用,用于创建一个新的进程。它是创建进程的核心函数之一,其特性和用法在进程管理中至关重要。本文将带你深入了解 fork() 函数的使用、返回值、常见问题及其在操作系统中的重要性。

fork() 函数概述

在 Linux 中,所有的进程都是通过 fork() 派生而来。当一个进程调用 fork() 时,操作系统会复制当前进程的上下文,为它创建一个几乎完全相同的副本,这个副本被称为子进程,而原始进程被称为父进程。

这也是人们口中的父子进程的概念

父子进程

进程a->fork->进程b

  • 我们称作进程a进程b的父进程,反之进程b则是进程a的子进程

fork函数

我们在命令终端,可以轻易的使用man手册来看,这个函数的作用返回值等,以及这个函数所需要的头文件是什么。

man 2 fork

fork() 是一个在Unix系统中可用的系统调用函数,用于创建一个新的进程。

fork() 函数的原型如下:

#include <unistd.h>

pid_t fork(void);

fork() 函数在调用时会复制当前进程创建一个新的子进程。子进程将几乎完全复制父进程的状态,包括代码、数据、打开的文件等。父进程和子进程之间的唯一区别是进程 ID(PID)和返回值。

  • 如果 fork() 返回 -1,则表示创建子进程失败。
  • 如果 fork() 返回 0,则表示当前代码运行在子进程中。
  • 如果 fork() 返回一个正整数,表示当前代码运行在父进程中,并且返回的值是子进程的PID

好,接着我们写一段调用fork函数的一个小demo

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
        pid_t pid;
        
        pid = fork();

        printf("pid = %d\n",pid);
        return 0;
}

在这里插入图片描述

编译运行后可以看到我的pid被打印了两次,也就是说我的printf函数被执行了两次。

结合我们提前整理的资料来看,使用fork之后返回的pid,一个是3403,一个是0,那么输出是0的这个应该是子进程打印的,那么另一个则是我的父进程打印的,这一区别使父子进程能够在相同的代码段内执行不同的操作。

例如,父进程可以根据 fork() 的返回值来监控子进程的运行状态,而子进程则可以独立执行任务。

我们升级这个程序继续观察一下。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	pid_t pid;
       
	printf("*********  test log 01 **********\n");

    pid = fork();
	printf("pid = %d\n",pid);
	
	if(pid == 0){
		printf("this is child\n");
		while(1){usleep(500);}
	}else{
		printf("this is father\n");
		while(1){usleep(500);}
	}


	return 0;
}

在这里插入图片描述
代码解释:
fork() 被调用时,系统会创建一个新进程。
代码中,pidfork() 的返回值,如果 pid == 0 表示这是子进程,否则就是父进程。
父进程可以通过 wait() 函数等待子进程执行完成。

这次在fork之前加了打印,可见在调用fork之前,我们的代码还是单进程再跑的。在fork之后也做了相关的判断,看到这里我想大家应该掌握了进程的奥秘了。

于是我们总结一下,写一个进程小框架,方便日后便捷使用。

#include <stdio.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();

    if (pid == -1) {
        // 创建子进程失败
        perror("fork failed");
    } else if (pid == 0) {
        // 子进程代码
        printf("Hello from child process!\n");
    } else {
        // 父进程代码
        printf("Hello from parent process!\n");
        printf("Child process ID: %d\n", pid);
    }

    return 0;
}

到了这里恭喜你,学会了进程,剩下的一些骚操作就是在此基础上不断的扩展延伸,以及迭代。
但是请注意
当一个进程调用fork()创建一个子进程时,子进程会复制父进程的内存空间,包括代码段、数据段、堆和栈等。这意味着在刚刚创建时,父进程和子进程的内存是一样的,但在后续的运行过程中,它们的内存是相互独立的。

现代操作系统中为了提高效率,通常使用写时复制(Copy-On-Write,COW )技术。

写时复制(Copy-On-Write,COW )
这意味着在 fork() 后,父子进程共享相同的内存页,直到其中一个进程试图修改这些页时,操作系统才会真正复制这些页。这样可以显著减少内存的占用,优化性能。

fork() 的常见问题

  • 僵尸进程(Zombie Process):如果父进程在子进程结束后未调用 wait() 或 waitpid() 函数读取子进程的状态信息,子进程将成为僵尸进程。这会占用系统资源,导致系统无法创建新的进程。
  • 多次 fork():如果不慎多次调用 fork(),可能会产生大量子进程,消耗系统资源,甚至造成“fork 炸弹”(即创建太多进程导致系统资源耗尽,系统崩溃)。
  • COW 效率:尽管写时复制提高了效率,但在高负载情况下,COW 的性能可能会受限。

Copy-On-Write(COW)是一种内存管理技术,通常用于优化进程之间的内存共享和复制操作。在 COW 机制中,当多个进程共享同一块内存时,只有在其中一个进程尝试修改这块内存时,系统才会执行复制操作,确保每个进程都能看到自己的独立副本,从而实现了延迟复制的效果。
COW 的效率主要体现在以下几个方面:

  1. 节省内存开销:COW 允许多个进程共享同一块内存,避免了不必要的内存复制。只有在必要的时候才会进行复制,从而节省内存开销。
  2. 减少复制时间:由于只有在写入操作时才会执行复制,因此在大多数情况下,COW 可以减少复制所需的时间,提高了操作的效率。
  3. 提高性能:通过延迟复制操作,COW 可以提高程序的性能,特别是在需要频繁复制内存数据的情况下,避免了不必要的复制开销。

fork() 的优势与限制

  • 优势:fork() 是创建子进程的简单方式,适合多任务并行处理的应用场景。写时复制机制降低了资源消耗,提升了系统效率。
  • 限制:在资源受限的嵌入式系统或实时系统中,频繁使用 fork() 可能导致性能下降。此外,不恰当的 fork() 使用可能引发僵尸进程或系统资源耗尽等问题。

结论

fork() 是 Linux 系统中关键的系统调用,理解它的行为和特性是掌握 Linux 进程管理的关键一步。掌握 fork() 的用法和注意事项,可以帮助开发者设计出高效、健壮的多进程应用。在实际开发中,fork() 通常与 execwait 等函数配合使用,以满足多任务系统的要求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2227228.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 8 下载与安装攻略

MySQL是一个流行的关系型数据库管理系统&#xff0c;目前MySQL属于Oracle公司的&#xff0c;关于MySQL的详细介绍可以参考&#xff1a; MySQL 的完整介绍 本篇主要关注MySQL 的下载和安装。 MySQL 下载 官方下载 进入MySQL 的下载页面 &#xff1a;https://dev.mysql.com/do…

HarmonyOS 鸿蒙开发 路由跳转报错this uri is empty, not support in route push.

检查方案1&#xff1a; 工程目录下 entry > src > main > resources > base > profile > main_pages.json中检查是否配置了NextPage 检查方案2&#xff1a; 在路由跳转的代码中检查是否路径配置错误 这里要注意&#xff0c;url的路径一定要和main_pages.json…

芯片上音频相关的验证

通常芯片设计公司&#xff08;比如QUALCOMM&#xff09;把芯片设计好后交由芯片制造商&#xff08;比如台积电&#xff09;去生产&#xff0c;俗称流片。芯片设计公司由ASIC部门负责设计芯片。ASIC设计的芯片只有经过充分的验证&#xff08;这里说的验证是FPGA&#xff08;现场…

【VSCode】配置

安装插件 C vscode-icons gdb调试 https://www.bilibili.com/video/BV15U4y1x7b2/?spm_id_from333.999.0.0&vd_sourcedf0ce73d9b9b61e6d4771898f1441f7f https://www.bilibili.com/video/BV1pU4y1W74Z?spm_id_from333.788.recommend_more_video.-1&vd_sourcedf0…

springboot使用枚举作为接口的参数

1.定义枚举类 2.定义接口 3.具体实现方法 4.apifox传入参数 枚举的具体’名称’就可以了 5.调试 6.进入断点&#xff0c;这样我们发现在接口的参数就映射到应的枚举类上了

数据结构(8.4_3)——堆的插入删除

在堆中插入新元素 在堆中删除元素 总结&#xff1a;

《计算机网络网络层:连接虚拟世界的关键桥梁》

一、网络层概述 网络层在计算机网络中占据着至关重要的地位&#xff0c;它作为连接不同网络的关键层次&#xff0c;起着承上启下的作用。网络层的主要任务是实现网络互连&#xff0c;将数据设法从源端经过若干个中间节点传送到目的端&#xff0c;为分组交换网上的不同主机提供通…

【linux】fdisk磁盘分区管理

介绍 fdisk是一个磁盘分区管理工具&#xff0c;可以用来创建、删除、修改和查看磁盘分区。 fdisk一般都是交互式使用&#xff0c;基础语法: fdisk /dev/sdd。进入交互窗口后&#xff0c;有一些选项&#xff0c;需要了解下&#xff1a; 选项含义n创建新分区p查看磁盘的分区情…

项目成本管理系统有哪些功能?9款工具详解

本文推荐的9大主流项目成本管理工具有: 1. PingCode&#xff1b;2. Worktile&#xff1b;3. 用友U8项目管理&#xff1b;4. 金蝶K3 Cloud&#xff1b;5. 泛微e-Project&#xff1b;6. 亿方云项目管理&#xff1b; 7. SAP Project System&#xff1b; 8. Trello&#xff1b; 9. …

基于opencv的眼镜试戴系统

对于正在准备毕业设计或者想在技术项目上加点“创新”的同学们&#xff0c;推荐一款基于OpenCV的眼镜试戴系统&#xff01;这不仅是一个实现个人创意的项目&#xff0c;更是一个结合AI技术和实用应用的完美范例。 &#x1f31f; 系统核心功能&#xff1a; 图片试戴&#xff1a…

解决cuda环境使用dgl

Dgl 是实现图结构数据构造的工具包&#xff0c;想在gpu环境下使用它&#xff0c;如果安装的是pip install dgl 会有下面错误 dgl._ffi.base.DGLError: [09:10:13] /opt/dgl/src/runtime/c_runtime_api.cc:82: Check failed: allow_missing: Device API cuda is not enabled. P…

软考高级备考记录

一 报考条件和报名流程 报考条件 该考试具有水平考试性质&#xff0c;报考任何级别不需要学历、资历条件&#xff0c;只要达到相应的专业技术水平就可以报考相应的级别 报名流程 软考报名官网&#xff1a;中国计算机技术职业资格网 官网上有 报名时间&#xff0c;考试…

springboot077基于SpringBoot的汽车票网上预订系统--论文pf(论文+源码)_kaic

汽车票网上预订系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了汽车票网上预订系统的开发全过程。通过分析汽车票网上预订系统管理的不足&#xff0c;创建了一个计算机管理汽车票网上预订系统的方案。文章…

vue使用xlsx以及file-saver进行下载xlsx文件以及Unit8Array、ArrayBuffer、charCodeAt的使用

先说Unit8Array、ArrayBuffer、charCodeAt的使用下面会用到这三个 Unit8Array&#xff1a;数组类型表示一个 8 位无符号整型数组&#xff0c;创建时内容被初始化为 0。创建完后&#xff0c;可以以对象的方式或使用数组下标索引的方式引用数组中的元素。 new Uint8Array(); //…

Python中的数据可视化:Matplotlib基础与高级技巧

Python中的数据可视化&#xff1a;Matplotlib基础与高级技巧 数据可视化是数据分析和数据科学中不可或缺的一部分。通过图表&#xff0c;我们可以更直观地观察数据的分布和趋势。Matplotlib作为Python最基础、也是最广泛使用的绘图库之一&#xff0c;不仅支持多种常用图表&…

Android Studio中Gradle一直在加载怎么解决(首次安装过程中)

目录 前言&#xff1a;遇到问题&#xff1a;已解决&#xff1a; 前言&#xff1a; Android Studio中Gradle一直在加载怎么解决&#xff08;首次安装过程中&#xff09;&#xff0c;在安装Android Studio的过程中&#xff0c;我因为环境的问题&#xff0c;被困扰了一天&#xf…

合合信息发布智能文档处理“百宝箱”,助力文档应用开发

文档是知识传递的载体&#xff0c;无论是大模型应用发展&#xff0c;还是与产业数字化息息相关的高质量数据库的建立&#xff0c;都离不开对于文档数据的处理和分析。目前&#xff0c;越来越多的开发者开始关注文档数据处理背后的“文档解析”技术&#xff0c;用以实现自动化数…

python常见内置函数

介绍Python常见的内置函数。 1、abs 取一个数的绝对值 int_value -2 print(abs(int_value))2、all 若一个可迭代对象(可循环遍历的对象)中所有元素为真&#xff0c;结果为真 list_value1 [1,2,3,4,0] list_value2 [1,2,3,4] print(all(list_value1)) print(all(list_va…

【cmake实战六】如何使用编译的库(动态库dll)——windows系统

【cmake实战六】如何使用编译的库&#xff08;动态库dll&#xff09;——windows系统_make windows下生成库-CSDN博客 基于以上文章&#xff0c;遇到的一些问题&#xff1a; 一、首先我用vs code 新建了一个项目&#xff1a;TEST 新增文件&#xff1a;CMakeList.txt #…

Kafka 与传统 MQ 消息系统之间有三个关键区别?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka 与传统 MQ 消息系统之间有三个关键区别&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; Kafka 与传统 MQ 消息系统之间有三个关键区别&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 …