进程间的IPC通信机制

一、介绍

进程与进程间的用户空间相互独立,内核空间共享。

1.传统的进程间通信机制

        a.无名管道 pipe

        b.有名管道 fifo

        c.信号         signal

2.system V中的IPC对象

        a.消息队列 message queue

        b.共享内存 shared memory

        c.信号灯集 semaphoare

3.可用于跨主机传输的通信机制

        a.套接字 socket

二、管道

1.管道可以看成是一个特殊文件,一般文件存储在外存中,而管道内容存储在内存中

2.管道遵循先进先出原则

3.管道的读操作是一次性的,内容被读出后就会从管道中删除

4.管道是一种半双工的通信方式

5.管道只能使用文件IO函数,因为需要直接操作内核空间,如open,close,read,write,但不能使用lseek

6.管道的大小为64k

2.1无名管道

无名管道即在文件系统(用户系统)不可见的管道文件

无名管道不可以用open打开,因为不知道路径以及名字

无名管道只能用于具有亲缘关系的进程间通信。由于无名管道在文件系统中不可见,两个无关的进程,无法拿到同一根管道的读写段,只有具有亲缘关系的进程,在父进程中创建一根管道,拿到读写端后,调用fork函数,创建出来的子进程也会有该管道的读写端。

从管道中读取数据:
1.读写端均存在时,当管道中没有数据时,read会阻塞

2.当管道的写端不存在时,若管道中有数据,会先将数据读取完毕,没有数据时,read函数不会阻塞,直接返回0

向管道中写入数据:

1.读写段均存在时,write会阻塞

2.当管道的读端不存在时,调用write函数,尝试向管道中写入数据会导致管道破裂。

#include <head.h>
int main(int argc, char const *argv[])
{// 管道的创建必须放在fork前// 若放在fork后,会导致父子进程各自创建一个内管道,无法通信int pfd[2] = {0};if (pipe(pfd) < 0) // pf[0]为读的文件描述符,pf[1]为写的文件描述符{perror("pipe");return -1;}printf("管道创建成功\n");pid_t pid = fork();if (pid > 0){// 父进程发数据给子进程char buf[128] = "";while (1){fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0; // 从终端获取数据,将最后获取到的\n变成\0// 将数据写入到管道中if (write(pfd[1], buf, sizeof(buf)) < 0){perror("write");return -1;}printf("写入成功\n");}}else if (pid == 0){// 子进程接收父进程发送过来的数据char buf[128] = "";int res = 0;while (1){// 管道中没有数据时,read会阻塞res = read(pfd[0], buf, sizeof(buf));printf("读取成功\n");printf("%s\n", buf);}}else{perror("fork");return -1;}return 0;
}

 2.2有名管道

写端

#include <head.h>
int main(int argc, char const *argv[])
{umask(0);// 创建有名管道if (mkfifo("./myfifo", 0664) < 0){if (errno != 17){ // 文件已存在的错误是一个合法的错误,需要排除,代码允许正常运行perror("mkfifo");return -1;}}printf("有名管道创建成功\n");// 以只写的方式打开有名管道int fd = open("./myfifo", O_WRONLY); // 当只有一个写端时,open函数会阻塞if (fd < 0){perror("open");return -1;}printf("open succcess\n");char buf[128] = "";while (1){printf("请输入>>>");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;if (write(fd, buf, sizeof(buf)) < 0){perror("write");return -1;}if (strcmp(buf, "quit") == 0)break;printf("写入成功\n");}close(fd);return 0;
}

读端

#include <head.h>
int main(int argc, char const *argv[])
{umask(0);// 创建有名管道if (mkfifo("./myfifo", 0664) < 0){if (errno != 17){ // 文件已存在的错误是一个合法的错误,需要排除,代码允许正常运行perror("mkfifo");return -1;}}printf("有名管道创建成功\n");// 以只读的方式打开有名管道int fd = open("./myfifo", O_RDONLY); // 当只有一个读端时,open函数会阻塞if (fd < 0){perror("open");return -1;}printf("open succcess\n");char buf[128] = "";int res = 0;while (1){bzero(buf, sizeof(buf));res = read(fd, buf, sizeof(buf));if (res < 0){perror("read");return -1;}else if ((res == 0) || strcmp(buf, "quit") == 0){printf("写端退出\n");break;}printf("buf=%s\n", buf);}close(fd);return 0;
}

三、信号

原理

信号是一种异步通信的方式

异步:任务与任务之间无关系,根据CPU轮询机制来运行多个任务

同步:任务与任务之间有先后关系,必须要等任务A结束2后才能执行任务B

1.signal

#include <head.h>void handler(int sig)
{printf("sig=%d\n", sig);return;
}
int main(int argc, char const *argv[])
{// 捕获2)SIGINT信号if (signal(2, handler) == SIG_ERR)//第一个参数:指定要捕获的信号,天对应的编号或宏//第二个参数:可以填SIG_IGN:忽略信号//SIG_DFL:执行默认操作//捕获信号信号:填写函数指针变量{perror("signal");return -1;}printf("捕获信号成功\n");while (1){printf("主函数\n");sleep(1);}return 0;
}

 

练习:用信号的方式回收僵尸进程

#include <head.h>
int count = 0;void handler(int sig)
{while (waitpid(-1, NULL, WNOHANG) > 0);
}
int main(int argc, char const *argv[])
{// 捕获17)SIGCHLD__sighandler_t s = signal(17, handler);if (SIG_ERR == s){perror("signal");return -1;}int i = 0;while (i < 100){int res = fork();if (res == 0)exit(0);i++;}while (1)sleep(1);return 0;
}

2.kill

当收到quit时,父子进程全部退出

#include <head.h>
int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid > 0){while (1){printf("父进程 %d %d\n", getpid(), pid);sleep(1);}}else if (pid == 0){char buf[128] = "";bzero(buf, sizeof(buf));while (1){printf("请输入>>>");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;printf("buf=%s", buf);if (strcmp(buf, "quit") == 0){break;}}// 子进程给父进程发信号,请求父进程退出kill(getppid(), 9); // 9号是杀死信号}else{perror("fork");return -1;}return 0;
}

3.alarm

设置3秒的定时器

#include <head.h>
void callback(int sig)
{printf("超时了\n");alarm(3);return;
}
int main(int argc, char const *argv[])
{// 捕获14号信号if (signal(14, callback) == SIG_ERR){perror("signal");return -1;}alarm(3);while (1){printf("signal....\n");sleep(1);}return 0;
}

四、消息队列

消息队列按照先进先出的原则,但也可以限制消息类型读取

消息队列独立于进程,等进程结束后,消息队列以及其中的内容不会删除,除非重启操作系统或手动删除

发送数据

#include <head.h>
struct msgbuf
{long mtype;      // 消息类型,必须大于0char mtext[128]; // 消息内容
};
int main(int argc, char const *argv[])
{// 创建key值key_t key = ftok("/home/ubuntu/", 1);// 第二个参数:填非0if (key < 0){perror("ftok");return -1;}// 创建消息队列int msqid = msgget(key, IPC_CREAT | 0664);if (msqid < 0){perror("msgget");return -1;}struct msgbuf sndbuf;while (1){printf("请输入人消息类型>>>");scanf("%ld", &sndbuf.mtype);getchar();if (sndbuf.mtype == 0){ // 若输入类型为0,退出循环break;}printf("请输入消息内容>>>");fgets(sndbuf.mtext, sizeof(sndbuf.mtext), stdin);sndbuf.mtext[strlen(sndbuf.mtext) - 1] = 0;// 向消息队列中发送数据if (msgsnd(msqid, &sndbuf, sizeof(sndbuf.mtext), 0) < 0){perror("msgsnd");return -1;}printf("发送成功\n");}// 删除消息队列if (msgctl(msqid, IPC_RMID, NULL) < 0){perror("msgctl");return -1;}printf("删除消息队列成功\n");return 0;
}

 

接收数据

#include <head.h>
struct msgbuf
{long mtype;      // 消息类型,必须大于0char mtext[128]; // 消息内容
};
int main(int argc, char const *argv[])
{// 创建key值key_t key = ftok("/home/ubuntu/", 1);// 第二个参数:填非0if (key < 0){perror("ftok");return -1;}// 创建消息队列int msqid = msgget(key, IPC_CREAT | 0664);if (msqid < 0){perror("msgget");return -1;}struct msgbuf recvbuf;int res = 0;while (1){// 从指定的消息队列中读取数据// 读取消息队列中的第一条消息,先进先出res = msgrcv(msqid, &recvbuf, sizeof(recvbuf.mtext), 0, IPC_NOWAIT);if (res < 0){perror("msgrcv");return -1;}printf("接收到的消息为%s\n", recvbuf.mtext);}// 删除消息队列if (msgctl(msqid, IPC_RMID, NULL) < 0){perror("msgctl");return -1;}printf("删除消息队列成功\n");return 0;
}

五、共享内存

共享内存是最高效的进程间通信方式

多个进程可以同时访问共享内存,修改其中的内容,所以共享内存其实是临界资源,需要注意进程间的同步互斥

共享内存独立于进程,等进程结束后,共享内存以及其中的内容不会删除,除非重启操作系统或者手动删除

发送数据

#include <head.h>
int main(int argc, char const *argv[])
{// 创建key值key_t key = ftok("./", 10);if (key < 0){perror("ftok");return -1;}printf("key=%#x\n", key);// 创建共享内存,获得shmid号int shmid = shmget(key, 32, IPC_CREAT | 0664);if (shmid < 0){perror("shmget");return -1;}printf("shmid=%d\n", shmid);// 映射共享内存到用户空间void *addr = shmat(shmid, NULL, 0);if (addr == (void *)-1){perror("shmat");return -1;}// 先往共享内存中存储一个int类型的数据*(int *)addr = 10;// 再往int类型数据后面存储一个字符串char *ptr = (char *)addr + 4;strcpy(ptr, "hello world");return 0;
}

接收数据

#include <head.h>
int main(int argc, char const *argv[])
{// 创建key值key_t key = ftok("./", 10);if (key < 0){perror("ftok");return -1;}// 创建共享内存,获得shmid号int shmid = shmget(key, 32, IPC_CREAT | 0664);if (shmid < 0){perror("shmget");return -1;}// 映射共享内存到用户空间void *addr = shmat(shmid, NULL, 0);if (addr == (void *)-1){perror("shmat");return -1;}printf("%d\n", *(int *)addr);printf("%s\n", (char *)((int *)addr + 1));return 0;
}

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

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

相关文章

vue前端时间段选择控件

实现效果: 可选具体的某天的某时某分某秒 vue前端代码: <el-form-item label"日期"><el-date-pickerv-model"daterangerq"style"width: 240px"value-format"yyyy-MM-dd HH:mm:ss"type"datetimerange"range-separat…

JetsonNano —— 3、在Nano板卡编译可硬件加速FFmpeg,测试FFmpeg调用nvmpi编解码器加速

最终FFmpeg运行加速效果如下: FFmpeg 简介 一个完整的跨平台解决方案,用于录制、转换和流式传输音频和视频。   JetsonNano 简介 NVIDIA Jetson Nano为数百万台高性能、低功耗设备提供前所未有的功能。这项技术创新为网络录像机、机器人或具有高级分析功能的智能家居网关等…

基于SPWM控制策略的二极管钳位型NPC逆变器的并网simulink仿真

本人搭建了二极管钳位型NPC并网逆变器simulink仿真模型&#xff0c;该模型型采用d、q轴&#xff0c;电压前馈解耦控制&#xff0c;三相逆变并网&#xff0c;PI控制&#xff0c;仿真复现&#xff0c;效果优异&#xff0c;适合新手学习使用。 模型获取链接&#xff1a;基于SPWM…

【MySQL探索之旅】JDBC (Java连接MySQL数据库)

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更…

探索免费静态IP海外的奥秘

在数字化时代&#xff0c;网络资源的获取和利用对于个人和企业都至关重要。其中&#xff0c;独立静态IP地址更是因其稳定性和安全性备受青睐。本文将带您深入了解“免费的独立静态IP海外”的奥秘&#xff0c;探讨其背后的原理、优势、获取途径以及使用场景。 一、独立静态IP的基…

XEChat-Idea:摸鱼神器!!【送源码】

XEChat-Idea ❝ 基于Netty的IDEA即时聊天插件 ❞ 项目介绍 主要功能&#xff1a; 即时聊天 游戏对战 即时聊天 idea摸鱼工具 idea斗地主 项目结构 . ├── LICENSE ├── README.md ├── xechat-commons //公共模块 │ ├── pom.xml │ └── src ├── xech…

文本分类的深度注意图扩散网络 笔记

1 Title Deep Attention Diffusion Graph Neural Networks for Text Classification&#xff08;Yonghao Liu、Renchu Guan、Fausto Giunchiglia、Yanchun Liang、Xiaoyue Feng&#xff09;【EMnlp 2021】 2 Conclusion Text classification is a fundamental task with broad…

Linux-- 重定向缓冲区

目录 0.接上篇文章 1.粗略的见一下这两个问题 2.理解重定向 3.理解缓冲区 0.接上篇文章 Linux--基础IO&#xff08;文件描述符fd&#xff09;-CSDN博客 1.粗略的见一下这两个问题 先来了解几个函数&#xff1a; stat()函数用于获取指定文件或符号链接的元数据。如果文件是…

Android 系统省电软件分析

1、硬件耗电 主要有&#xff1a; 1、屏幕 2、CPU 3、WLAN 4、感应器 5、GPS(目前我们没有) 电量其实是目前手持设备最宝贵的资源之一&#xff0c;大多数设备都需要不断的充电来维持继续使用。不幸的是&#xff0c;对于开发者来说&#xff0c;电量优化是他们最后才会考虑的的事情…

【C++】详解STL的适配器容器之一:优先级队列 priority_queue

目录 堆算法 概述 向下调整建堆 向上调整建堆 建堆算法 仿函数 概述 使用介绍 emtpy size top push pop 模拟实现 仿函数 框架 向下调整算法 向上调整算法 pop push empty top 要理解优先级队列&#xff0c;需要有如下知识 STL容器之一的vector&#xf…

聚类分析 | 基于GA遗传算法优化kmeans聚类(Matlab)

聚类分析 | 基于GA遗传算法优化kmeans聚类&#xff08;Matlab&#xff09; 目录 聚类分析 | 基于GA遗传算法优化kmeans聚类&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 GA-kmeans聚类算法&#xff0c;通过GA遗传算法优化kmeans聚类&…

【python】模块与包

Python中的模块和包是组织和管理代码的重要工具。通过模块和包&#xff0c;你可以更好地管理和重用你的代码&#xff0c;使得代码更加模块化和可维护。 目录 前言 正文 一、模块 1、模块的分类 1&#xff09;内置模块 python解释器中默认拥有的模块可以直接使用&#xff08;…

用户需求甄别和筛选的6大标准

产品经理日常经常接收到大量的需求&#xff0c;并不是所有的需求都需要开发&#xff0c;需要进行甄别和筛选&#xff0c;这样有利于确保项目的成功、优化资源利用以及提高产品质量。 那么针对这些用户需求进行甄别或筛选的评判标准是什么&#xff1f;需求筛选可以说是初步的需求…

代码随想录-算法训练营day31【贪心算法01:理论基础、分发饼干、摆动序列、最大子序和】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第八章 贪心算法 part01● 理论基础 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和 贪心算法其实就是没有什么规律可言&#xff0c;所以大家了解贪心算法 就了解它没有规律的本质就够了。 不用花心思去研究其…

C++牛客周赛题目分享(2)小红叕战小紫,小红的数组移动,小红的素数合并,小红的子序列求和

目录 ​编辑 1.前言 2.四道题目 1.小红叕战小紫 1.题目描述 2.输入描述 3.输出描述 4.示例 5.题解与思路 2.小红的数组移动 1.题目描述 2.输入描述 3.输出描述 4.示例 5.题解与思路 3.小红的素数合并 1.题目描述 2.输入描述 3.输出描述 4.示例 5.题解与思…

云原生新手和开源教育分论坛 01-Kubernetes 社区:从新手到影响者

2024年04月20日 上海KCD & Shanghai&#xff1a;https://community.cncf.io/events/details/cncf-kcd-shanghai-presents-kcd-shanghai-2024/视频观看&#xff1a;https://www.bilibili.com/video/BV1nD421T786/?spm_id_from333.999.0.0&vd_sourceae7b192be069682aabc…

【FreeRTOS 快速入门】-- 1、STM32工程移植FreeRTOS

目录 一、新建STM32工程 为了示范完整的移植过程&#xff0c;我们从0开始&#xff0c;新建一个标准的STM32点灯工程。 &#xff08;本篇以CubeMX作示范&#xff0c;CubeIDE操作近同&#xff0c;可作对比参考&#xff09; 1、新建工程 选择 芯片型号 新建工程 2、搜索芯片型号…

24年做抖音小店,你还停留在数据?别人都已经开始注重利润了

大家好&#xff0c;我是电商笨笨熊 一件事情持续做&#xff0c;一个项目持续深耕&#xff0c;意义到底是什么&#xff1f; 这句话我常常说&#xff0c;但很多人似乎走偏了实际意义&#xff1b; 尤其对于新手来说&#xff0c;做抖音小店总是向往某某老玩家多么牛的数据&#…

程序员健康指南:运动,让代码更流畅

程序员健康指南&#xff1a;运动&#xff0c;让代码更流畅 程序员&#xff0c;一个与电脑相伴的群体&#xff0c;长时间的久坐和高强度的脑力劳动是他们的日常。然而&#xff0c;久坐不仅影响体态&#xff0c;更对心脏健康构成威胁。根据《欧洲心脏杂志》的研究&#xff0c;中…

【PPT技巧】ppt文件打开就是只读模式,如何改为可编辑模式?

PPT文档打开是只读模式&#xff0c;如何改成可编辑文档呢&#xff1f;这需要分几种情况来说&#xff0c;所以今天将介绍几种方法帮助PPT只读文档改为可编辑文档。 方法一&#xff1a; 我们可以先查看一下文件属性&#xff0c;属性中有只读属性&#xff0c;当我们打开文档之后带…