嵌入式Linux系统编程 — 7.4 fork、vfork函数创建子进程

news2024/11/17 17:31:17

目录

1 父进程与子进程概念

2 fork创建子进程

3  系统调用 vfork()函数

4 vfork与 fork函数如何选择


1 父进程与子进程概念

进程与子进程是操作系统中的一个基本概念,用于描述进程之间的层级关系。下面是对这一概念的简要说明:

  • 父进程:在操作系统中,创建新进程的现有进程被称为父进程。父进程可以生成一个或多个子进程,并且通常在子进程执行期间继续运行。

  • 子进程:由父进程创建的进程称为子进程。子进程可以是父进程的一个副本,继承父进程的某些资源和属性,也可以是完全不同的进程,执行不同的任务。

父进程与子进程有如下的关系:

  • 父子关系:子进程通常继承父进程的资源,如文件描述符、环境变量等,但它们拥有自己的地址空间和代码执行路径。父进程和子进程可以通过进程间通信(IPC)机制进行数据交换,如管道、消息队列、共享内存等。

  • 生命周期:子进程的生命周期可以独立于父进程,即使父进程结束,子进程也可以继续运行,如果父进程没有等待子进程就终止了,子进程会变成“僵尸进程”,直到被操作系统回收。

2 fork创建子进程

在诸多的应用中,创建多个进程是任务分解时行之有效的方法,譬如,某一网络服务器进程可在监听客户端请求的同时,为处理每一个请求事件而创建一个新的子进程,与此同时,服务器进程会继续监听更多的客户端连接请求。在一个大型的应用程序任务中,创建子进程通常会简化应用程序的设计,同时提高了系统的并发性。

一个现有的进程可以调用 fork()函数创建一个新的进程, 调用 fork()函数的进程称为父进程,由 fork()函数创建出来的进程被称为子进程 , fork()函数原型如下所示:

#include <unistd.h>

pid_t fork(void);
  • 返回值fork() 调用在父进程中返回子进程的 PID,在子进程中返回 0。

下面是 fork() 函数的示例程序,使用它来创建一个新的进程: 

#include <stdio.h>
#include <unistd.h> // 包含fork函数的头文件

int main() 
{
    int pid = fork(); // 创建新进程

    if (pid < 0) {
        // fork失败
        fprintf(stderr, "Fork failed");
        return 1;
    } else if (pid == 0) {
        // 这是子进程
        printf("This is the child process. PID: %d\n", getpid());
    } else {
        // 这是父进程
        printf("This is the parent process. PID: %d, Child PID: %d\n", getpid(), pid);
    }

    // 父进程和子进程都可以继续执行以下代码
    printf("Parent and child continue to execute...\n");

    return 0;
}

fork() 调用会返回两次:一次在父进程中,返回子进程的PID;一次在子进程中,返回0。如果 fork() 调用失败,它会在父进程中返回一个负值。

3  系统调用 vfork()函数

vfork()是Linux系统中的一个系统调用,用于创建一个新的进程。与 fork() 函数不同,vfork() 创建的子进程会立即暂停,直到父进程调用 exec() 系列函数或者子进程退出。这种特性使得 vfork() 适合于那些创建子进程后立即调用 exec() 替换子进程映像的场景,因为它避免了父进程和子进程之间的上下文切换。vfork()函数原型如下所示:

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

pid_t vfork(void);

下面是一个使用 vfork() 的简单示例程序:

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

int main() 
{
    pid_t pid = vfork(); // 创建新进程

    if (pid < 0) {
        // vfork失败
        perror("vfork failed");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 这是子进程,应该尽快调用exec()系列函数
        // 这里使用execl()作为示例
        execl("/bin/ls", "ls", "-l", NULL);
        // 如果execl调用失败,输出错误信息并退出
        perror("execl failed");
        _exit(EXIT_FAILURE);
    } else {
        // 这是父进程
        printf("This is the parent process. PID: %d, Child PID: %d\n", getpid(), pid);
    }

    // 父进程的其他代码可以继续执行

    return 0;
}

如果 vfork() 成功,它会返回子进程的PID给父进程,返回0给子进程。如果调用失败,它会返回-1给父进程,并设置 errno 以指示错误。程序的运行结果如下:

  1. 父进程的进程ID(PID)是 5321。
  2. 子进程的进程ID(PID)是 5322。
  3. 子进程执行了 ls -l 命令,列出了当前目录下的文件和目录。

4 vfork与 fork函数如何选择

vfork()与 fork()函数主要有以下两个区别:

  • vfork()与 fork()一样都创建了子进程,但 vfork()函数并不会将父进程的地址空间完全复制到子进程中,因为子进程会立即调用 exec(或_exit) ,于是也就不会引用该地址空间的数据。不过在子进程调用 exec 或_exit 之前,它在父进程的空间中运行、 子进程共享父进程的内存。这种优化工作方式的实现提高的效率; 但如果子进程修改了父进程的数据、进行了函数调用、或者没有调用 exec 或_exit 就返回将可能带来未知的结果。
  • 另一个区别在于, vfork()保证子进程先运行, 子进程调用 exec 之后父进程才可能被调度运行。

虽然 vfork()系统调用在效率上要优于 fork(),但是 vfork()可能会导致一些难以察觉的程序 bug,所以尽量避免使用 vfork()来创建子进程,虽然 fork()在效率上并没有 vfork()高,但是现代的 Linux 系统内核已经采用了写时复制技术来实现 fork(),其效率较之于早期的 fork()实现要高出许多,除非速度绝对重要的场合,我们的程序当中应舍弃 vfork()而使用 fork()。
 

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

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

相关文章

线程池的合理使用

线程池的合理使用 一、简介二、为什么要使用线程池三、核心参数四、如何合理配置线程参数1.1 corePoolSize && maximumPoolSize1.2 Handler 拒绝策略1.2.1AbortPolicy&#xff1a;优势&#xff1a;劣势&#xff1a; 1.2.2 DiscardPolicy&#xff1a;优势&#xff1a;劣…

3Python的Pandas:数据选取

1.数据选取操作 1.1. 选取单列 df[Q1]df[Q2]1.2. 选取多列 df[[team,Q1]]df.loc[:,[team,Q1]]1.3.选择行 使用指定索引选择 df[df.indexAck]选择前n行 df[0:3]df.iloc[:10,:]1.4. 前n行&#xff0c;每隔m选择一个 df[0:10:3]1.5. 条件选择 df[df.Q1>90]df[(df.teamC…

linxu驱动入门基础课一(GPIO控制LED灯)基于RK3568

虽然GPIO控制LED 是最简单的linux驱动&#xff0c;但是是初学者入门必须跨过的门槛&#xff0c;里面很多基础知识点&#xff0c;有GPIO的控制原理&#xff0c;字符设备驱动&#xff0c;设备树&#xff0c;gpio和pinctrl子系统&#xff0c;内核模块原理等等&#xff0c;这些知识…

APP明暗主题设置

1.preference.xml 增加一个暗色主题 SwitchPreference 2.每个 Activity 的 setContentView 前面增加 setTheme SharedPreferences sharedPreferences PreferenceManager.getDefaultSharedPreferences(this); if (sharedPreferences.getBoolean("switch_dark_theme"…

Windows下编译OpenSSL静态库

目录 1. 版本与下载地址 2. 下载与安装VS2015 3. 下载与安装Perl 4. 测试ActivePerl是否安装正确 5. 下载OpenSSL 6. 编译32位OpenSSL静态库 6.1 解压openssl-1.0.2l.tar.gz 6.2 打开VS2015 x86本机工具命令提示符 6.3 输入命令进入到openssl的目录中 6.4 执行配置命…

加密与安全_密钥体系的三个核心目标之不可否认性解决方案

文章目录 Pre概述不可否认性数字签名&#xff08;Digital Signature&#xff09;证书是什么证书使用流程 PKICA证书层级多级证书证书链是如何完成认证的&#xff1f; 其他疑问1. Alice能直接获取Bob的公钥&#xff0c;是否还需要证书&#xff1f;2. 为什么即使能直接获取公钥也…

世界人工智能大会 | 江行智能大模型解决方案入选“AI赋能新型工业化创新应用优秀案例”

日前&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议在上海启幕。本次大会主题为“以共商促共享&#xff0c;以善治促善智”&#xff0c;汇聚了上千位全球科技、产业界领军人物&#xff0c;共同探讨大模型、数据、新型工业化等人工智能深度发展时代下的热点话题…

CLIP编码器调用时刚开始正常,然后输出全部变为NaN

碰到了这个问题&#xff1a;输入是正常的&#xff0c;输出全是NaN 网上办法不多&#xff0c;找了半天终于看到问题所在&#xff0c;但是没有说在哪里改的&#xff0c;故记录一下。 改一下模型精度就正常了&#xff0c;默认的是fp16&#xff0c;改为fp32即可 具体步骤如下&…

渲染引擎之ECS架构介绍

1.什么是ECS&#xff1f; 我们先简单地介绍一下什么是ECS&#xff1a; E -- Entity 实体&#xff0c;本质上是存放组件的容器C -- Component 组件&#xff0c;引擎所需的所有数据结构S -- System 系统&#xff0c;根据组件数据处理逻辑状态的管理器 ECS全称Entity-Component-…

免费压缩pdf文件大小软件收费吗?pdf如何压缩文件大小?12款压缩应用推荐!

在数字化时代&#xff0c;PDF文件因其跨平台、格式统一的特点而广受欢迎。然而&#xff0c;随着文件内容的增加&#xff0c;PDF文件的大小也逐渐增大&#xff0c;给存储和传输带来了诸多不便。因此&#xff0c;寻找一款合适的PDF压缩软件成为了许多用户的需求。本文将详细介绍1…

阿里开源语音理解和语音生成大模型FunAudioLLM

近年来&#xff0c;人工智能&#xff08;AI&#xff09;的进步极大地改变了人类与机器的互动方式&#xff0c;例如GPT-4o和Gemin-1.5等。这种转变在语音处理领域尤为明显&#xff0c;其中高精度的语音识别、情绪识别和语音生成等能力为更直观、更类人的交互铺平了道路。阿里开源…

# 昇思25天学习打卡营第10天 | 使用静态图加速

昇思25天学习打卡营第10天 | 使用静态图加速 文章目录 昇思25天学习打卡营第10天 | 使用静态图加速动态图的开启方式静态图的开启方式基于全局context的开启方式基于修饰器的开启方式 总结打卡 AI编译框架分为两种运行模式&#xff1a; 动态图模式&#xff1a; 计算图的构建和计…

C语言 | Leetcode C语言题解之第224题基本计算器

题目&#xff1a; 题解&#xff1a; int calculate(char* s) {int n strlen(s);int ops[n], top 0;int sign 1;ops[top] sign;int ret 0;int i 0;while (i < n) {if (s[i] ) {i;} else if (s[i] ) {sign ops[top - 1];i;} else if (s[i] -) {sign -ops[top - 1…

android文本长按复制

android文本长按复制 &#x1f4d6;1. 长按直接复制✅步骤一&#xff1a;定义一个TextView✅步骤二&#xff1a;为TextView注册长按事件✅步骤三&#xff1a;弹出系统复制功能 &#x1f4d6;2. 长按弹框确认复制✅步骤一&#xff1a;定义一个TextView✅步骤二&#xff1a;封装P…

3d模型设计要注意什么?---模大狮模型网

展览3D模型设计作为现代展示和艺术表达的重要手段&#xff0c;不仅仅是简单的视觉元素&#xff0c;更是整个展览体验的核心。在这个领域&#xff0c;设计师需要综合考虑美学、功能性以及技术实现的多重因素。本文将探讨在展览3D模型设计过程中需要注意的关键要点。 一、美学与视…

70.WEB渗透测试-信息收集- WAF、框架组件识别(10)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;69.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;9&#xff09; 关于waf相应的识…

Java并发/多线程CompleteableFuture详解

目录 CompleteableFuture 创建 获得结果的方法 辅助方法 allOf和anyOf的区别 CompletableFuture 里大约有五十种方法&#xff0c;但是可以进行归类: 变换类 thenApply 消费类 thenAccept 执行操作类 thenRun thenApply/thenAccept/thenRun 结合转化类 thenCombine 结…

C++ 类和对象 构造 / 析构函数

一 类的6个默认成员函数&#xff1a; 如果一个类中什么成员都没有&#xff0c;简称为空类。 例&#xff1a; #include <iostream> class Empty {// 空类&#xff0c;什么成员都没有 }; 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&a…

使用预加载库优化 PostgreSQL 函数#postgresql认证

在 POSTGRESQL 中执行函数和过程 为了理解 PostgreSQL 的工作原理&#xff0c;我们首先要看一个简单的函数调用。下一个清单显示了一些简单的PostGIS代码&#xff1a; PgSQL test# timing Timing is on. test# SELECT * FROM hans.points WHERE id 1;id │ …