当前位置: 首页 > 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. 选中所有类…...

Mongodb数组字段索引之多键索引

学习mongodb&#xff0c;体会mongodb的每一个使用细节&#xff0c;欢迎阅读威赞的文章。这是威赞发布的第92篇mongodb技术文章&#xff0c;欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题&#xff0c;欢迎在文章下面点个赞&#xff0c;或者关…...

[Spring] Spring Web MVC案例实战

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…...

大模型“重构”教育:解构学习奥秘,推动教育普惠

大模型“重构”千行百业系列选题 生成式人工智能的热潮&#xff0c;为AI领域的发展注入新的活力&#xff0c;而“赋能千行百业”已经成为人们普遍对于人工智能和大模型的全新理解。 人工智能和大模型技术的迅猛发展正在以前所未有的速度深刻改变着各个行业。正如专家所预测&a…...

HCNA VRP基础

交换机可以隔离冲突域&#xff0c;路由器可以隔离广播域&#xff0c;这两种设备在企业网络中应用越来越广泛。随着越来越多的终端接入到网络中&#xff0c;网络设备的负担也越来越重&#xff0c;这时网络设备可以通过专有的VRP系统来提升运行效率。通过路由平台VRP是华为公司数…...

单片机外围设备-EEPROM

eeprom用iic通信。eeprom有几个特点需要关注&#xff1a; 1、可以单字节读写 2、eeprom按页划分存储&#xff0c;不同型号的eeprom的页大小不一致&#xff0c;往eeprom写数据时&#xff0c;如果写到了该页的末尾&#xff0c;会自动从该页的开头继续写&#xff0c;把之前的数据…...

YOLO--置信度(超详细解读)

YOLO&#xff08;You Only Look Once&#xff09;算法中的置信度&#xff08;Confidence&#xff09;是一个关键概念&#xff0c;用于评估模型对预测框内存在目标对象的信心程度以及预测框对目标对象位置的准确性。 一、置信度的定义 数值范围&#xff1a;置信度是一个介于0和…...

“解锁物流新纪元:深入探索‘沂路畅通‘分布式协作平台“

"解锁物流新纪元&#xff1a;深入探索沂路畅通分布式协作平台" 在21世纪的数字浪潮中&#xff0c;物流行业作为连接生产与消费的关键纽带&#xff0c;其重要性不言而喻。然而&#xff0c;随着市场规模的持续扩大和消费者需求的日益多样化&#xff0c;传统物流模式已…...

昇思25天学习打卡营第六天|应用实践/计算机视觉/Vision Transformer图像分类

心得 运行模型似乎有点靠天意&#xff1f;每次跑模型之前先来个焚香沐浴&#xff1f;总之今天是机器视觉的最后一课了&#xff0c;尽管课程里强调模型跑得慢&#xff0c;可是我的这次运行&#xff0c;居然很快的就看到结果了。 如果一直看我这个系列文章的小伙伴&#xff0c;…...

vxe-table合并行数据

场景&#xff1a; 混批名称相同合并混批名称&#xff0c;在混批名称相同条件下合并相同的混批类型&#xff1b;在混混批类型相同条件下合并相同的混批值&#xff1b;在混批值相同条件下合并相同的单位 实现根据四个不同的key值&#xff0c;当四个key值对应相等时&#xff0c;合…...

LabVIEW异步和同步通信详细分析及比较

1. 基本原理 异步通信&#xff1a; 原理&#xff1a;异步通信&#xff08;Asynchronous Communication&#xff09;是一种数据传输方式&#xff0c;其中数据发送和接收操作在独立的时间进行&#xff0c;不需要在特定时刻对齐。发送方在任何时刻可以发送数据&#xff0c;而接收…...