当前位置: 首页 > news >正文

Linux 多进程编程详解

Linux 多进程编程详解

多进程编程是现代操作系统中一种重要的并发编程技术。通过在同一程序中运行多个独立的进程,可以实现并发处理,充分利用多核处理器的优势,提高程序的运行效率。本文将详细介绍Linux多进程的基本概念、创建方法、进程间通信、同步机制以及实际应用,配以C++示例代码,帮助读者深入理解和掌握多进程编程技术。

1. 多进程的基本概念

在Linux操作系统中,进程是程序的一个实例,是系统进行资源分配和调度的基本单位。每个进程都有独立的地址空间和资源,包括代码段、数据段、堆、栈以及文件描述符等。进程之间通过进程间通信(IPC)机制进行通信和同步。多进程编程就是在同一程序中创建并运行多个进程,以实现并发处理。

1.1 进程的生命周期

进程的生命周期包括以下几个状态:

创建(New):进程被创建,但尚未准备好执行。
就绪(Ready):进程已准备好执行,但尚未被分配CPU时间。
运行(Running):进程正在执行。
阻塞(Blocked):进程正在等待某些事件(如I/O操作)发生。
终止(Terminated):进程已完成执行或被终止。

进程的状态转换如下图所示:

     +-------------------+|     创建 (New)    |+-------------------+|v+-------------------+|     就绪 (Ready)  |+-------------------+|v+-------------------+|     运行 (Running)|+-------------------+|v+-------------------+|    阻塞 (Blocked) |+-------------------+|v+-------------------+|    终止 (Terminated)|+-------------------+

进程由操作系统调度,从创建到就绪,再从就绪状态转移到运行状态。如果进程在运行过程中需要等待某些事件(如I/O操作),则会进入阻塞状态。当等待的事件发生时,进程重新进入就绪状态,等待调度运行。当进程完成任务或被终止时,进入终止状态。

1.2 进程控制块(PCB)

进程控制块(PCB,Process Control Block)是操作系统管理进程的主要数据结构,包含了进程的各种信息,包括:

进程标识符(PID):每个进程都有一个唯一的标识符。
进程状态:表示进程当前的状态(创建、就绪、运行、阻塞、终止)。
程序计数器(PC):保存进程下一条将要执行的指令地址。
寄存器:保存进程的上下文信息。
内存管理信息:包括进程的地址空间、页表等信息。
I/O状态信息:包括打开的文件描述符、I/O设备等信息。

PCB是操作系统进行进程切换和调度的重要依据。

2. 进程的创建

在Linux中,可以通过fork()系统调用创建一个新的进程。fork()会创建一个子进程,该子进程是父进程的副本,继承了父进程的所有资源和上下文。子进程有自己独立的地址空间,父子进程可以并发运行。

2.1 fork()系统调用

fork()系统调用的原型如下:

pid_t fork(void);

fork()返回两次,一次在父进程中返回子进程的PID,一次在子进程中返回0。如果fork()失败,则返回-1:

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>int main() {pid_t pid = fork(); // 创建一个子进程if (pid < 0) {// fork失败std::cerr << "Fork failed!" << std::endl;return 1;} else if (pid == 0) {// 子进程std::cout << "Hello from Child Process!" << std::endl;std::cout << "Child Process ID: " << getpid() << std::endl;std::cout << "Parent Process ID: " << getppid() << std::endl;} else {// 父进程std::cout << "Hello from Parent Process!" << std::endl;std::cout << "Parent Process ID: " << getpid() << std::endl;std::cout << "Child Process ID: " << pid << std::endl;// 等待子进程结束int status;waitpid(pid, &status, 0);if (WIFEXITED(status)) {std::cout << "Child process exited with status: " << WEXITSTATUS(status) << std::endl;}}return 0;
}

在上述代码中,fork()创建了一个子进程。父进程和子进程分别打印各自的PID和相关信息,并通过waitpid()等待子进程结束。

2.2 进程的终止

进程在完成任务后会终止,终止进程可以通过exit()系统调用实现。exit()系统调用的原型如下:

void exit(int status);

其中,status是进程的退出状态码,通常为0表示正常退出,非0表示异常退出。

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>int main() {pid_t pid = fork();if (pid < 0) {std::cerr << "Fork failed!" << std::endl;return 1;} else if (pid == 0) {// 子进程std::cout << "Hello from Child Process!" << std::endl;std::cout << "Child Process ID: " << getpid() << std::endl;std::cout << "Parent Process ID: " << getppid() << std::endl;exit(0); // 子进程正常退出} else {// 父进程std::cout << "Hello from Parent Process!" << std::endl;std::cout << "Parent Process ID: " << getpid() << std::endl;std::cout << "Child Process ID: " << pid << std::endl;// 等待子进程结束int status;waitpid(pid, &status, 0);if (WIFEXITED(status)) {std::cout << "Child process exited with status: " << WEXITSTATUS(status) << std::endl;}}return 0;
}
3. 进程间通信

进程间通信(IPC)是多进程编程中的重要部分,用于在独立的进程之间传递数据和信息。常见的IPC机制包括管道、消息队列、共享内存和信号等。

3.1 管道(Pipe)

管道是一种半双工的通信机制,只能在父子进程或兄弟进程之间使用。管道由两个文件描述符组成,一个用于读端,一个用于写端。使用pipe()系统调用创建管道。

#include <iostream>
#include <unistd.h>
#include <cstring>int main() {int fd[2];if (pipe(fd) == -1) {std::cerr << "Pipe failed!" << std::endl;return 1;}pid_t pid = fork();if (pid < 0) {std::cerr << "Fork failed!" << std::endl;return 1;} else if (pid == 0) {// 子进程close(fd[0]); // 关闭读端const char* msg = "Hello from Child Process!";write(fd[1], msg, strlen(msg) + 1); // 写入管道close(fd[1]); // 关闭写端} else {// 父进程close(fd[1]); // 关闭写端char buffer[100];read(fd[0], buffer, sizeof(buffer)); // 从管道读取std::cout << "Parent Process received: " << buffer << std::endl;close(fd[0]); // 关闭读端}return 0;
}

在上述代码中,父子进程通过管道实现通信。子进程将消息写入管道,父进程从管道读取消息。

3.2 消息队列(Message Queue)

消息队列是一种消息传递机制,允许进程以消息的形式进行通信。消息队列是一个链表,每个消息包含一个消息类型和消息数据。使用msgget()、msgsnd()和msgrcv()系统调用管理消息队列。

#include <iostream>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <cstring>struct message {long msg_type;char msg_text[100];
};int main() {key_t key = ftok("progfile", 65); // 生成唯一键int msgid = msgget(key, 0666 | IPC_CREAT); // 创建消息队列message msg;msg.msg_type = 1;strcpy(msg.msg_text, "Hello from Child Process!");pid_t pid = fork();if (pid < 0) {std::cerr << "Fork failed!" << std::endl;return 1;} else if (pid == 0) {// 子进程,发送消息msgsnd(msgid, &msg, sizeof(msg.msg_text), 0);std::cout << "Message sent from Child Process." << std::endl;} else {// 父进程,接收消息msgrcv(msgid, &msg, sizeof(msg.msg_text), 1, 0);std::cout << "Parent Process received: " << msg.msg_text << std::endl;// 删除消息队列msgctl(msgid, IPC_RMID, NULL);}return 0;
}

在上述代码中,父子进程通过消息队列实现通信。子进程发送消息,父进程接收消息。

共享内存(Shared Memory)

共享内存是一种高效的进程间通信机制,允许多个进程共享一块内存区域。使用 shmget()、shmat() 和 shmdt() 系统调用管理共享内存。

共享内存是所有 IPC 机制中最快的一种,因为进程可以直接访问内存中的数据,而不需要通过内核中介。但是,这也意味着需要额外的同步机制来确保多个进程不会同时修改共享数据而导致数据不一致。

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cstring>int main() {key_t key = ftok("shmfile", 65); // 生成唯一键int shmid = shmget(key, 1024, 0666 | IPC_CREAT); // 创建共享内存pid_t pid = fork();if (pid < 0) {std::cerr << "Fork failed!" << std::endl;return 1;} else if (pid == 0) {// 子进程,写入共享内存char* str = (char*) shmat(shmid

好了,今天的分享到这里就结束了,感谢大家的支持!

相关文章:

Linux 多进程编程详解

Linux 多进程编程详解 多进程编程是现代操作系统中一种重要的并发编程技术。通过在同一程序中运行多个独立的进程&#xff0c;可以实现并发处理&#xff0c;充分利用多核处理器的优势&#xff0c;提高程序的运行效率。本文将详细介绍Linux多进程的基本概念、创建方法、进程间通…...

C语言之大小端理解

目录 1前言2 大小端理解与区分3 大小端的识别和基本切换操作4 总结 1前言 在汽车CAN通讯报文中往往会接触到Intel类型和motorola类型&#xff0c;实际项目中涉及到多机通讯也会接触到大小端问题 2 大小端理解与区分 大端(Big_Endian) :低字节放在高地址小端(Little_Endian):…...

GIT相关操作,推送本地分支到远程仓库流程记录学习

git流程 切换到源文件夹&#xff1a;cd 源文件夹克隆远程仓库&#xff1a;git clone [ssh]进入项目文件夹&#xff1a;cd .\project\查看本地分支&#xff1a;git branch获取远程仓库更新&#xff0c;使远程同步&#xff1a;git fetch查看所有分支&#xff08;包括远程分支&am…...

网络协议 — Keepalived 高可用方案

目录 文章目录 目录Keepalived 是实现了 VRRP 协议的软件Keepalived 的软件架构VRRP StackCheckersKeepalived 的配置Global configurationvrrp_scriptVRRP Configurationvrrp synchroization groupvrrp instancevirtual ip addressesvirtual routesLVS Configurationvirtual_s…...

前端报错adding CSS “touch-action: none“ to this element解决方案

目录 如图所示控制台出现报错&#xff1a; 原因&#xff1a; touch-action 介绍&#xff1a; 解决方案&#xff1a; 1.手动设置touch-action&#xff1a; 2.使用条件渲染&#xff1a; 3.CSS样式隔离&#xff1a; 4.浏览器兼容性&#xff1a; 5. 忽略警告 如图所示控制台…...

使用phpMyAdmin操作MYSQL(四)

一. 学会phpMyAdmin&#xff1f; phpMyAdminhttp://water.ve-techsz.cn/phpmyadmin/ 虽然我我们可以用命令行操作数据库&#xff0c;但这样难免没有那么直观&#xff0c;方便。所以接下来我们使用phpMyAdmin来操作MySQL&#xff0c;phpMyAdmin是众多MySQL图形化管理工具中使用…...

webpack配置代理请求

在 Webpack 中&#xff0c;可以通过配置devServer中的proxy选项来设置代理请求&#xff0c;以解决开发环境中的跨域问题或实现特定的请求转发逻辑。以下是一个常见的 Webpack 配置示例&#xff0c;展示了如何设置代理&#xff1a; module.exports {// 其他配置项...devServer…...

热门软件缺陷管理工具2024:专业评测与建议

国内外主流的10款软件缺陷管理工具软件对比&#xff1a;PingCode、Worktile、禅道、Tapd、Teambition、Tower、JIRA、Bugzilla、MantisBT、Trac。 在软件开发过程中&#xff0c;管理缺陷和漏洞常常成为一项挑战&#xff0c;尤其是在项目规模庞大时。选择一个高效的软件缺陷管理…...

冒泡,选择,插入,希尔排序

目录 一. 冒泡排序 1. 算法思想 2. 时间复杂度与空间复杂度 3. 代码实现 二. 选择排序 1. 算法思想 2. 时间复杂度与空间复杂度 3. 代码实现 三.插入排序 1. 直接插入排序 (1). 算法思想 (2). 时间复杂度与空间复杂度 (3). 代码实现 2. 希尔排序 (1). 算法思想 …...

【HarmonyOS学习】Calendar Kit日历管理

简介 Calendar Kit提供日历与日程管理能力&#xff0c;包括日历的获取和日程的创建能力。 Calendar Kit为用户提供了一系列接口来获取日历账户&#xff0c;并使用特定的接口向日历账户中写入日程。 如果写入的日程带有提醒时间则系统会在时间到达时向用户发送提醒。 约束点…...

RDMA 高性能架构基本原理与设计方案

RDMA的主要优点包括低延迟、高吞吐量、减少CPU负担和支持零拷贝网络。它允许数据直接在网络接口卡&#xff08;NIC&#xff09;和内存之间传输&#xff0c;减少了数据传输过程中的中间环节&#xff0c;从而显著降低了延迟。RDMA技术能够实现高速的数据传输&#xff0c;适用于需…...

【Springboot】事件机制发布与订阅的使用实践

文章目录 为什么要使用事件监听机制概念和原理使用场景用户注册系统实践案例1. 创建事件类2. 发布事件3. 监听事件3.1 通过注解EventListener实现监听3.2 通过实现ApplicationListener接口实现监听 4. 测试事件机制 总结 为什么要使用事件监听机制 在Springboot中&#xff0c;…...

新版网页无插件H.265播放器EasyPlayer.js如何测试demo视频?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff1b;支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#xff0…...

PXE、Kickstart和cobbler

一.系统装机 1.1 三种引导方式 启动操作系统 1.硬盘 2.光驱(u盘) 3.网络启动 pxe 1.2 系统安装过程 1.加载boot loader: Boot Loader 是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设 备、建立内存空间的映射图,从而将系统的软硬…...

【GameFramework扩展应用】6-3、GameFramework框架增加日志保存功能

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群:398291828大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录: https://blog.csdn.net/q764424567/article/details/1…...

将独热码应用到神经网络中

引言 接上回&#xff0c;本文继续说如何用TensorFlow将独热编码应用到一个简单的神经网络中&#xff0c;以实现从一段随机文本到另一段随机文本的转换。 步骤一&#xff1a;导入库 import tensorflow as tf import numpy as np import random import string步骤二&#xff1…...

在CSS中,使用Flexbox布局时,可以通过几个属性来控制容器内的项目之间的间距

display弹性布局&#xff0c;flex:1是占据剩下的空间 关于displa:flex /* 水平和垂直居中&#xff0c;水平和垂直方向上的间距均匀分布 / .container { display: flex; justify-content: space-between; / 左右对齐 / align-items: center; / 上下间距 */ flex-direction: ro…...

关于HDFS 和HBase

Apache HBase 被设计为在 Hadoop 分布式文件系统 (HDFS) 上运行的一个特殊类型的数据库。大白话&#xff1a; 想象一下&#xff0c;你有一个巨大的图书馆&#xff0c;这个图书馆就像 HDFS&#xff0c;它的架子上堆满了各种各样的书籍&#xff0c;每本书都非常厚&#xff0c;而…...

【HarmonyOS】HarmonyOS NEXT学习日记:二、ArkTs语法

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;二、ArkTs语法 众所周知TS是JS的超集,而ArkTs则可以理解为是Ts的超集。他们的基础都基于JS&#xff0c;所以学习之前最好就JS基础。我的学习重点也是放在ArkTs和JS的不同点上。 文章主要跟着官方文档学习&#xff0c;跳过了一…...

Web前端-Web开发CSS基础2-选择器

一. 基础 1. 选中所有的<p>标签&#xff1b; 2. 选中所有的<ol>标签&#xff1b; 3. 选中所有的<ul>标签&#xff1b; 4. 选中所有id为happy的标签&#xff1b; 5. 选中所有id为sad的标签&#xff1b; 6. 选中所有id为angry的标签&#xff1b; 7. 选中所有类…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

Oracle11g安装包

Oracle 11g安装包 适用于windows系统&#xff0c;64位 下载路径 oracle 11g 安装包...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...