【在Linux世界中追寻伟大的One Piece】进程间通信

目录

1 -> 进程间通信介绍

1.1 -> 进程间通信目的

1.2 -> 进程间通信发展

1.3 -> 进程间通信分类

1.3.1 -> 管道

1.3.2 -> System V IPC

1.3.3 -> POSIX IPC

2 -> 管道

2.1 -> 什么是管道

2.2 -> 匿名管道

2.3 -> 实例代码

2.4 -> 用fork来共享管道原理

2.5 -> 站在文件描述符角度——深度理解管道

2.6 -> 站在内核角度——管道本质

3 -> 管道读写规则

4 -> 管道特点


1 -> 进程间通信介绍

1.1 -> 进程间通信目的

  • 数据传输:一个进程需要将它的数据发送给另一个进程。
  • 资源共享:多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

1.2 -> 进程间通信发展

  • 管道
  • System V进程间通信
  • POSIX进程间通信

1.3 -> 进程间通信分类

1.3.1 -> 管道

  • 匿名管道pipe
  • 命名管道

1.3.2 -> System V IPC

  • System V消息队列
  • System V共享内存
  • System V信号量

1.3.3 -> POSIX IPC

  • 消息队列
  • 共享内存
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁

2 -> 管道

2.1 -> 什么是管道

  • 管道是Unix中最古老的进程间通信的形式。
  • 我们把从一个进程连接到另一个进程的一个数据流称为一个"管道"。

2.2 -> 匿名管道

#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码

2.3 -> 实例代码

#define _CRT_SECURE_NO_WARNINGS 1

//例子:从键盘读取数据,写入管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
	int fds[2];
	char buf[100];
	int len;
	if (pipe(fds) == -1)
		perror("make pipe"), exit(1);

	// read from stdin
	while (fgets(buf, 100, stdin)) 
	{
		len = strlen(buf);
		// write into pipe
		if (write(fds[1], buf, len) != len) 
		{
			perror("write to pipe");

			break;
		}

		memset(buf, 0x00, sizeof(buf));

		// read from pipe
		if ((len = read(fds[0], buf, 100)) == -1) 
		{
			perror("read from pipe");

			break;
		}

		// write to stdout
		if (write(1, buf, len) != len) 
		{
			perror("write to stdout");

			break;
		}
	}
}

2.4 -> 用fork来共享管道原理

2.5 -> 站在文件描述符角度——深度理解管道

2.6 -> 站在内核角度——管道本质

所以,看待管道,就如同看待文件一样!管道的使用和文件一致,迎合了"Linux一切皆文件思想"。

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

#define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0)
int main(int argc, char* argv[]) 
{
	int pipefd[2]; 
	if (pipe(pipefd) == -1) 
		ERR_EXIT("pipe error");

	pid_t pid;
	pid = fork();
	if (pid == -1)
		ERR_EXIT("fork error");

	if (pid == 0) 
	{
		close(pipefd[0]);
		write(pipefd[1], "hello", 5);
		close(pipefd[1]);

		exit(EXIT_SUCCESS);
	}

	close(pipefd[1]);
	char buf[10] = { 0 };
	read(pipefd[0], buf, 10);

	printf("buf=%s\n", buf);

	return 0;
}

例1. 在minishell中添加管道的实现:

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

# define MAX_CMD 1024

char command[MAX_CMD];

int do_face()
{
	memset(command, 0x00, MAX_CMD);
	printf("minishell$ ");
	fflush(stdout);
	if (scanf("%[^\n]%*c", command) == 0) 
	{
		getchar();

		return -1;
	}

	return 0;
}

char** do_parse(char* buff)
{
	int argc = 0;
	static char* argv[32];
	char* ptr = buff;
	while (*ptr != '\0') 
	{
		if (!isspace(*ptr)) 
		{
			argv[argc++] = ptr;
			while ((!isspace(*ptr)) && (*ptr) != '\0') 
			{
				ptr++;
			}
		}
		else 
		{
			while (isspace(*ptr)) 
			{
				*ptr = '\0';
				ptr++;
			}
		}
	}

	argv[argc] = NULL;

	return argv;
}

int do_redirect(char* buff)
{
	char* ptr = buff, * file = NULL;
	int type = 0, fd, redirect_type = -1;
	while (*ptr != '\0') 
	{
		if (*ptr == '>') 
		{
			*ptr++ = '\0';
			redirect_type++;
			if (*ptr == '>') 
			{
				*ptr++ = '\0';
				redirect_type++;
			}

			while (isspace(*ptr)) 
			{
				ptr++;
			}

			file = ptr;
			while ((!isspace(*ptr)) && *ptr != '\0') 
			{
				ptr++;
			}

			*ptr = '\0';
			if (redirect_type == 0) 
			{
				fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, 0664);
			}
			else 
			{
				fd = open(file, O_CREAT | O_APPEND | O_WRONLY, 0664);
			}

			dup2(fd, 1);
		}

		ptr++;
	}

	return 0;
}

int do_command(char* buff)
{
	int pipe_num = 0, i;
	char* ptr = buff;
	int pipefd[32][2] = { {-1} };
	int pid = -1;
	pipe_command[pipe_num] = ptr;
	while (*ptr != '\0') 
	{
		if (*ptr == '|') 
		{
			pipe_num++;
			*ptr++ = '\0';
			pipe_command[pipe_num] = ptr;

			continue;
		}

		ptr++;
	}

	pipe_command[pipe_num + 1] = NULL;

	return pipe_num;
}

int do_pipe(int pipe_num)
{
	int pid = 0, i;
	int pipefd[10][2] = { {0} };
	char** argv = { NULL };
	for (i = 0; i <= pipe_num; i++) 
	{
		pipe(pipefd[i]);
	}

	for (i = 0; i <= pipe_num; i++) 
	{
		pid = fork();
		if (pid == 0) 
		{
			do_redirect(pipe_command[i]);
			argv = do_parse(pipe_command[i]);
			if (i != 0) 
			{
				close(pipefd[i][1]);
				dup2(pipefd[i][0], 0);
			}

			if (i != pipe_num) 
			{
				close(pipefd[i + 1][0]);
				dup2(pipefd[i + 1][1], 1);
			}

			execvp(argv[0], argv);
		}
		else 
		{
			close(pipefd[i][0]);
			close(pipefd[i][1]);
			waitpid(pid, NULL, 0);
		}
	}

	return 0;
}

int main(int argc, char* argv[])
{
	int num = 0;
	while (1) 
	{
		if (do_face() < 0)
			continue;

		num = do_command(command);
		do_pipe(num);
	}

	return 0;
}

3 -> 管道读写规则

  • 当没有数据可读时:
    • O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
    • O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
  • 当管道满的时候:
    • O_NONBLOCK disable: write调用阻塞,直到有进程读走数据。
    • O_NONBLOCK enable:调用返回-1,errno值为EAGAIN。
  • 如果所有管道写端对应的文件描述符被关闭,则read返回0。
  • 如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出。
  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
  • 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

4 -> 管道特点

  • 只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
  • 管道提供流式服务。
  • 一般而言,进程退出,管道释放,所以管道的生命周期随进程。
  • 一般而言,内核会对管道操作进行同步与互斥。
  • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。


感谢各位大佬支持!!!

互三啦!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java | Leetcode Java题解之第436题寻找右区间

题目&#xff1a; 题解&#xff1a; class Solution {public int[] findRightInterval(int[][] intervals) {int n intervals.length;int[][] startIntervals new int[n][2];int[][] endIntervals new int[n][2];for (int i 0; i < n; i) {startIntervals[i][0] inter…

回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于SO-SVR蛇群算法优化支持向量机的数据多输入单输出回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab基于SO-SVR蛇群算法优化支持向量机的数据多…

828华为云征文|华为云Flexus云服务器X实例——部署EduSoho网校系统、二次开发对接华为云视频点播实现CDN加速播放

EduSoho 是一款功能强大的网校系统&#xff0c;能够帮助教育机构快速搭建在线学习平台。本文将详细介绍如何在华为云服务器上安装和部署 EduSoho 网校系统&#xff0c;以及二次开发对接华为云视频点播VOD来实现CDN加速播放。 edusoho本地存储的视频播放存在诸多弊端。一方面&a…

建立分支提交代码

git分支 git branch 产看当前分支 git branch -a 查看所有分支 git checkout 分支名 切换分支 git checkout -b 分支名 建立分支&#xff08;仅仅是在本地建立了&#xff0c;并没有关联线上&#xff09; git push --set-upstream origin 分支名 把本地分支推到先线上 gti add …

Spring Boot 整合MyBatis-Plus 实现多层次树结构的异步加载功能

文章目录 1&#xff0c;前言2&#xff0c;什么是多层次树结构&#xff1f;3&#xff0c;异步加载的意义4&#xff0c;技术选型与实现思路5&#xff0c;具体案例5.1&#xff0c;项目结构5.2&#xff0c;项目配置&#xff08;pom.xml&#xff09;5.3&#xff0c;配置文件&#xf…

天龙八部怀旧单机微改人面桃花+安装教程+GM工具+虚拟机一键端

今天给大家带来一款单机游戏的架设&#xff1a;天龙八部怀旧单机微改人面桃花。 另外&#xff1a;本人承接各种游戏架设&#xff08;单机联网&#xff09; 本人为了学习和研究软件内含的设计思想和原理&#xff0c;带了架设教程仅供娱乐。 教程是本人亲自搭建成功的&#xf…

Excel 设置自动换行

背景 版本&#xff1a;office 专业版 11.0 表格内输入长信息&#xff0c;发现默认状态时未自动换行的&#xff0c;找了很久设置按钮&#xff0c;遂总结成经验帖。 操作 1&#xff09;选中需设置的单元格/区域/行/列。 2&#xff09;点击【开始】下【对齐方式】中的【自动换…

JUC高并发编程4:集合的线程安全

1 内容概要 2 ArrayList集合线程不安全 2.1 ArrayList集合操作Demo 代码演示 /*** list集合线程不安全*/ public class ThreadDemo4 {public static void main(String[] args) {// 创建ArrayList集合List<String> list new ArrayList<>();for (int i 0; i <…

【有啥问啥】具身智能(Embodied AI):人工智能的新前沿

具身智能&#xff08;Embodied AI&#xff09;&#xff1a;人工智能的新前沿 引言 在人工智能&#xff08;AI&#xff09;的进程中&#xff0c;具身智能&#xff08;Embodied AI&#xff09;正逐渐成为研究与应用的焦点。具身智能不仅关注于机器的计算能力&#xff0c;更强调…

count(1),count(*)与 count(‘列名‘) 的区别

文章目录 COUNT(expr)性能对比count(*) VS count(1)count(*) VS count(列名) count(*)会走索引吗MyISAM count优化InnoDB如何处理count(*)总结 参考官方文档&#xff1a; https://dev.mysql.com/doc/refman/8.4/en/aggregate-functions.html#function_count COUNT(expr) coun…

Skyeye 云这几年的经历

前言 我是 17 年毕业的&#xff0c;之前也是在学校的实验室 (做开发的) 待了两年多时间&#xff0c;期间学了不少东西&#xff0c;学的东西也算是与时俱进了。最近两年也算是开源中国的常客了&#xff0c;每周都会保持自己项目的一个更新进度。 项目地址&#xff1a;skyeye-o…

Chainlit集成LlamaIndex实现知识库高级检索(BM25全文检索器)

检索原理 BM25Retriever类是一个基于BM25算法设计的检索器&#xff0c;它主要用于从一组文档或节点中检索出与查询最相关的文档或节点。这个类的设计目的是为了提高文本检索的效率和准确性&#xff0c;尤其是在处理大量文本数据时。 BM25&#xff08;Best Matching 25&#x…

[uni-app]小兔鲜-03多端打包上线

小程序打包 打包上线流程 打包命令: pnpm build:mp-weixin效果预览: 把打包后的文件导入微信开发者工具 (dist\build\mp-weixin)代码上传: 点击微信开发者工具的上传按钮, 上传代码,审核发布: 登录微信公众平台, 提交审核, 审核后发布辅助工具: 有些团队会使用开发辅助工具 mi…

Android OpenGLES2.0开发(三):绘制一个三角形

我们总是对陌生人太客气&#xff0c;而对亲密的人太苛刻 上一篇文章中&#xff0c;我们已经将OpenGL ES环境搭建完成。接下来我们就可以开始我们的绘图之旅了。该篇我们讲解最基本图形三角形的绘制&#xff0c;这是一切绘制的基础。在OpenGL ES的世界里一切图形都可以由三角形拼…

基于nodejs+vue的农产品销售管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

基于微信小程序爱心领养小程序设计与实现(源码+参考文档+定制开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-23

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-23 本期&#xff0c;我们对大语言模型在表情推荐, 软件安全和 自动化软件漏洞检测等方面如何应用&#xff0c;提供几篇最新的参考文章。 1 Semantics Preserving Emoji Recommendation with Large Language Mod…

[深度学习]卷积神经网络CNN

1 图像基础知识 import numpy as np import matplotlib.pyplot as plt # 图像数据 #imgnp.zeros((200,200,3)) imgnp.full((200,200,3),255) # 可视化 plt.imshow(img) plt.show() # 图像读取 imgplt.imread(img.jpg) plt.imshow(img) plt.show() 2 CNN概述 卷积层convrelu池…

分布式数据库——HBase基本操作

启动HBase: 1.启动hadoop,进入hadoop的sbin中 cd /opt/hadoop/sbin/ 2.初始化namenode hdfs namenode -format 3.启动hdfs ./start-all.sh 4.启动hbase cd /opt/hbase/bin ./start-hbase.sh 5.使用jps查看进程 jps 以下图片则是hbase启动成功~ 运行HBase ./hbase sh…

64.【C语言】再议结构体(下)(未完)

本文衔接第63篇 目录 6.复习 7.修改默认对齐数 8.结构体传参 01.传递非指针参数 02.传递指针参数(传递地址) 03.对比 9.结构体实现位段 01.位段的定义 02.格式 03.例题 答案速查 分析 前置知识:位段的内存分配 解析 若按浪费空间处理 验证 6.复习 20.【C语言…