12-LINUX--进程间的通信

news2024/11/20 8:48:29

进程间通信:采用IPC机制(进程间的用户空间相互独立,内核空间共享),有管道,信号量,共享内存,消息队列,套接字。

一.管道

        管道可以用来在两个进程之间传递数据,如: ps -ef | grep “bash”, 其中‘|’就是管
道,其作用就是将 ps 命令的结果写入管道文件,然后 grep 再从管道文件中读出该数据进行
过滤。

1.1有名管道

        有名管道可以在任意两个进程之间通信
有名管道的创建:
        ◼ 命令创建: mkfifo FIFO
        ◼ 系统调用创建
#include <sys/types.h>
 #include <sys/stat.h>
 //filename 是管道名 mode 是创建的文件访问权限
 int mkfifo(const char *filename, mode_t mode);

a.c代码

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

int main()
{
        int fd = open("./fifo",O_WRONLY);
        if(fd ==-1)
        {
                exit(1);
        }
        printf("fd=%d\n",fd);
        while(1)
        {
        printf("intput:\n");
        char buff[128] ={0};
        fgets(buff,128,stdin);
        if(strncmp(buff,"end",3) ==0)
        {
                break;
        }
        write(fd,buff,strlen(buff));
        }
        close(fd);
}
                                                                  

b.c代码

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


int main()
{
        int fd = open("./fifo",O_RDONLY);
        printf("fd=%d\n",fd);
        if(fd ==-1)
        {
                exit(1);
        }
        while(1)
        {
        char buff[128];
        int n=read(fd,buff,127);
        if(n==0)
        {
                break;
        }
        printf("buff=%s\n",buff);
        }
        close(0);
        exit(0);
}
      

运行:

1.2无名管道

无名管道主要应用于父子进程间的通信。
无名管道的创建:
1. #include <unistd.h>
2. /*
3. pipe()成功返回 0,失败返回-1
4. fds[0]是管道读端的描述符
5. fds[1]是管道写端的描述符
6. */
7. int pipe(int fds[2]);
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
//无名管到
int main()
{
        int fd[2];//fd[0] r  fd[1]  w
        if(pipe(fd) == -1)
        {
                exit(1);
        }

        write(fd[1],"hello",5);
        char buff[128] ={0};
        read(fd[0],buff,127);
        printf("%s\n",buff);

        close(fd[0]);
        close(fd[1]);
        exit(0);
}

无名管道父子进程间的通信:

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

int main()
{
	int fd[2];//fd[0] r  fd[1]  w
	if(pipe(fd) == -1)
	{
		exit(1);
	}

	pid_t pid =fork();
	if(pid ==-1)
	{
		exit(1);
	}
	if(pid==0)
	{
		
		close(fd[1]);
		while(1)
		{
			char buff[128]={0};
			//read(fd[0],buff,127);
			if(read(fd[0],buff,127) == 0)
			{
				//printf("child read:%s\n",buff);
				break;
			}
			printf("chlid read:%s\n",buff);

		}
		close(fd[0]);
	}
	else
	{
	        close(fd[0]);
		while(1)
		{
			printf("input: ");
			char buff[128] ={0};
			fgets(buff,128,stdin);
			if(strncmp(buff,"end",3)==0)
			{
				break;
			}
			write(fd[1],buff,strlen(buff));
		}
		close(fd[1]);
	}
	exit(0);
}

1.3管道的特点

无论有名还是无名,写入管道的数据都在内存中
管道是一种半双工通信方式(通信方式有单工、半双工、全双工)
有名和无名管道的区别:有名可以在任意进程间使用,而无名主要在父子进程间

1.4管道的实现

二.信号量

由于父子进程间无法确定谁先谁后,所以运行结果会有顺序错乱的情况

提出使用信号量管理,使得父子进程间的通信变得有序

1.信号量

        信号量是一个特殊的变量,一般取正数值。它的值代表允许访问的资源数目,获取资源
时,需要对信号量的值进行原子减一,该操作被称为 P 操作。当信号量值为 0 时,代表没有
资源可用,P 操作会阻塞。释放资源时,需要对信号量的值进行原子加一,该操作被称为 V
操作。信号量主要用来同步进程。信号量的值如果只取 0,1,将其称为二值信号量。如果信
号量的值大于 1,则称之为计数信号量。
         临界资源:同一时刻,只允许被一个进程或线程访问的资源
        临界区:访问临界资源的代码段

2.信号量的使用

操作信号量的接口介绍:
 #include <sys/sem.h>
 #include <sys/types.h>
 #include <sys/ipc.h>
 /*
 semget()创建或者获取已存在的信号量
 semget()成功返回信号量的 ID, 失败返回-1
 key:两个进程使用相同的 key 值,就可以使用同一个信号量
 nsems:内核维护的是一个信号量集,在新建信号量时,其指定信号量集中信号
量的个数
 semflg 可选: IPC_CREAT IPC_EXCL
 */
 int semget(key_t key, int nsems, int semflg);

 /*
 semop()对信号量进行改变,做 P 操作或者 V 操作
 semop()成功返回 0,失败返回-1
 struct sembuf
 {
 unsigned short sem_num; //指定信号量集中的信号量下标
 short sem_op; //其值为-1,代表 P 操作,其值为 1,代表 V 操作
 short sem_flg; //SEM_UNDO
 };
 */
 int semop(int semid, struct sembuf *sops, unsigned nsops);
 /*
 semctl()控制信号量
 semctl()成功返回 0,失败返回-1
 cmd 选项: SETVAL IPC_RMID

 union semun
 {
 int val;
struct semid_ds *buf;
 unsigned short *array;
 struct seminfo *_buf;
 };
 */
int semctl(int semid, int semnum, int cmd, ...);
例题:进程 a 和进程 b 模拟访问打印机,进程 a 输出第一个字符‘a’表示开始使用打印
机,输出第二个字符‘a’表示结束使用,b 进程操作与 a 进程相同。(由于打印机同一时刻
只能被一个进程使用,所以输出结果不应该出现 abab),如图所示:

封装信号量的接口:

          sem.h 的代码如下:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/sem.h>

union semun
{
	int val;
};
void sem_init();
void sem_p();
void sem_v();
void sem_destroy();
sem.c 的代码如下:
#include "sem.h"

static int semid =-1;
void sem_init()
{
	semid =semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);
	if(semid == -1)
	{
		semid = semget((key_t)1234,1,IPC_CREAT|0600);//创建失败,说明已有,获取
		if(semid == -1)
		{
			printf("semget err\n");
			return;
		}
	}
	else//创建成功,初始化
	{
	 	union semun a;
		a.val =1;
		if(semctl(semid,0,SETVAL,a) == -1)
		{
			printf("semcrl setval err\n");
		}
	}
}
void sem_p()
{
	struct sembuf buf;
	buf.sem_num =0; //信号两的下标,目前只有一个,下标为0
	buf.sem_op =-1;//p
	buf.sem_flg = SEM_UNDO;

	if(semop(semid,&buf,1) == -1)
	{
		printf("semop p err\n");
	}
}
void sem_v()
{
	
	struct sembuf buf;
	buf.sem_num =0; //信号两的下标,目前只有一个,下标为0
	buf.sem_op =1;//v
	buf.sem_flg = SEM_UNDO;

	if(semop(semid,&buf,1) == -1)
	{
		printf("semop v err\n");
	}
}
void sem_destroy()//销毁信号量
{
	if(semctl(semid,0,IPC_RMID) == -1)
	{
		printf("semctl destroy err\n");
	}
}
a.c 的代码如下:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/sem.h>
#include"sem.h"
int main()
{
	sem_init();
	for(int i =0;i<5;i++)
	{
		sem_p();
		printf("A");
		fflush(stdout);
		int n = rand() %3;
		sleep(n);
		printf("A");
		fflush(stdout);;
		sem_v();
		n=rand() %3;
		sleep(n);
	}
}
//gcc -o a a.c sem.c
//gcc -o b b.c sem.c 

b.c代码:

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/sem.h>
#include"sem.h"
int main()
{
	sem_init();
	for(int i =0;i<5;i++)
	{
		sem_p();
		printf("B");
		fflush(stdout);
		int n = rand() %3;
		sleep(n);
		printf("B");
		fflush(stdout);
		sem_v();
		n=rand() %3;
		sleep(n);
	}
	sleep(10);
	sem_destroy();
}
运行结果如下图所示,输出结果只截了部分:
练习题: 三个进程 a、b、c 分别输入“A”、“B”、“C”,要求输出结果必须是“ABCABCABC…”

3.ipcs/ipcrm 介绍

ipcs 可以查看消息队列、共享内存、信号量的使用情况,使用 ipcrm 可以进行删除操作。

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

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

相关文章

C语言入门(第三天:函数、指针)

一、函数 1.1 函数概述 作用&#xff1a;提高代码的编写效率&#xff0c;实现对代码的重用 函数使用步骤 定义函数 理解为制作工具&#xff0c;工具只需要制作1次即可 调用函数 理解为使用工具 1.2 无参无返回值 1.3 有参无返回值(重点) 函数参数的作用&#xff1a;增加…

怎么提升公众号上限

正常可以申请多少个公众号&#xff1f;目前如果我们是企业主体的话&#xff08;包括个体户&#xff09;&#xff0c;申请公众号默认是可以申请2个公众号数量的。不过对于很多公司来说&#xff0c;2个公众号的数量肯定是远远不够用的&#xff0c;不同的产品不同品牌不同部门都可…

基于R语言实现的beta二项回归模型【理解与实现】

本实验&#xff0c;创建一组使用二项分布模拟的数据&#xff08;不带额外的随机性&#xff09;&#xff0c;和另一组使用Beta二项分布模拟的数据&#xff08;引入了随机成功概率 p&#xff0c;从而增加了数据的离散性。 现在假设我们站在上帝视角&#xff0c;有两组不知道分布…

【可能是全网最丝滑的LangChain教程】七、LCEL表达式语言

系列文章地址 【可能是全网最丝滑的LangChain教程】一、LangChain介绍-CSDN博客 【可能是全网最丝滑的LangChain教程】二、LangChain安装-CSDN博客 【可能是全网最丝滑的LangChain教程】三、快速入门LLM Chain-CSDN博客 【可能是全网最丝滑的LangChain教程】四、快速入门Re…

Oracle ORA-28547:connection to server failed,probable Oracle Net admin error

使用Navicat连接oracle数据库时报ORA-28547错误 因为Navicat自带的oci.dll并不支持oracle11g&#xff0c;需要去官网下载支持的版本。 1.去oracle下载对应的oci.dll文件 下载地址&#xff1a;Oracle Instant Client Downloads 可以用 11.2.0.4 2. 复制刚下载下来的instant…

【无人机/平衡车/机器人】详解STM32+MPU6050姿态解算—卡尔曼滤波+四元数法+互补滤波(文末附3个算法源码)

效果: MPU6050姿态解算-卡尔曼滤波+四元数+互补滤波 目录 基础知识详解 欧拉角

嵌入式第三天:(C语言入门)

目录 一、跳转关键字 break&#xff1a; continue&#xff1a; goto&#xff1a; 二、函数 概述&#xff1a; 函数的使用&#xff1a; 无参无返回值&#xff1a; 有参无返回值&#xff1a; 有参有返回值&#xff1a; 返回值注意点&#xff1a; 函数的声明&#xff…

微信跳转页面时发生报错

报错如下图所示&#xff1a; 解决方法&#xff1a;&#xff08;从下面四种跳转方式中任选一种&#xff0c;哪种能实现效果就用哪个&#xff09; 带历史回退 wx.navigateTo() //不能跳转到tabbar页面 不带历史回退 wx.redirectTo() //跳转到另一个页面wx.switchTab() //只能…

Linux: softirq 简介

文章目录 1. 前言2. softirq 实现2.1 softirq 初始化2.1.1 注册各类 softirq 处理接口2.1.2 创建 softirq 处理线程 2.2 softirq 的 触发 和 处理2.1.1 softirq 触发2.1.2 softirq 处理2.1.2.1 在 中断上下文 处理 softirq2.1.2.2 在 ksoftirqd 内核线程上下文 处理 softirq 3.…

[lesson26]类的静态成员函数

类的静态成员函数 静态成员函数 在C中可以定义静态成员函数 静态成员函数是类中特殊的成员函数静态成员函数属于整个类所有可以通过类名直接访问公有静态成员函数可以通过对象名访问公有静态成员函数 静态成员函数的定义 直接通过static关键字修饰成员函数 静态成员函数 vs…

4.Godot图片素材的获取和编辑

游戏开发中经常遇到图片素材的需求 1. 图片素材的准备 术语&#xff1a;Sprite 精灵&#xff0c;游戏开发中指一张图片来源不明的图片&#xff0c;切勿在商业用途使用&#xff0c;以免引起版权风险。 1. 在学习阶段&#xff0c;可以百度或者从一些资源网站获取&#xff0c;这…

Unity类银河恶魔城学习记录12-13 p135 Merge Skill Tree with Dogge skill源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili​​​​​​​ Inventory.cs using System.Collections.Generic; using Un…

分布式结构化数据表Bigtable

文章目录 设计动机与目标数据模型行列时间戳 系统架构主服务器Chubby作用子表服务器SSTable结构子表实际组成子表地址组成子表数据存储及读/写操作数据压缩 性能优化局部性群组&#xff08;Locality groups&#xff09;压缩布隆过滤器 Bigtable是Google开发的基于GFS和Chubby的…

Apple:叠加提示 - 高效的 RAG 优化方式

发表机构&#xff1a;Apple 本文介绍了一种新的检索增强生成&#xff08;RAG&#xff09;提示方法——叠加提示&#xff08;superposition prompting&#xff09;&#xff0c;该方法可以直接应用于预训练的基于变换器的大模型&#xff08;LLMs&#xff09;&#xff0c;无需微调…

cmake制作并链接动静态库

cmake制作并链接动静态库 制作静态库add_library(库名称 STATIC 源文件1 [源文件2] ...)LIBRARY_OUTPUT_PATH指定库的生成路径 制作动态库add_library(库名称 SHARED 源文件1 [源文件2] ...) 连接动静态库link_libraries连接静态库link_directories到哪个路径去找库target_link…

ssh爆破服务器的ip-疑似肉鸡

最近发现自己的ssh一直有一些人企图使用ssh暴力破解的方式进行密码破解.就查看了一下,真是网络安全太可怕了. 大家自己的服务器密码还是要设置好,管好,做好最基本的安全措施,不然最后只能沦为肉鸡. ssh登陆日志可以在/var/log下看到,ubuntu的话为auth.log,centos为secure文件 查…

ubuntu 应用程序设置 开机自启动

1. 通过.desktop方式 autostart 中.desktop 配置文件 1.1 用户级自启动 登录后才可以启动服务。 可视化配置&#xff1a;在ubuntu自带的可视化程序来配置&#xff0c;就是StartupApplications&#xff0c;它在启动台中可以找到。 在ubuntu下目录是 ~/.config/autostart 添…

kotlin项目引用

概要&#xff1a; 记录项目引用kotlin具体事项 1 object下build.gradle buildscript {//声明引用版本ext.kotlin_version "1.4.20"repositories {google()mavenCentral()}dependencies {classpath "com.android.tools.build:gradle:4.2.0"//引用kotlinc…

DataX案例,MongoDB数据导入HDFS与MySQL

【尚硅谷】Alibaba开源数据同步工具DataX技术教程_哔哩哔哩_bilibili 目录 1、MongoDB 1.1、MongoDB介绍 1.2、MongoDB基本概念解析 1.3、MongoDB中的数据存储结构 1.4、MongoDB启动服务 1.5、MongoDB小案例 2、DataX导入导出案例 2.1、读取MongoDB的数据导入到HDFS 2…

Ubuntu去除烦人的顶部【活动】按钮

文章目录 一、需求说明二、打开 extensions 网站三、安装 GNOME Shell 插件四、安装本地连接器五、安装 Hide Activities Button 插件六、最终效果七、卸载本地连接器命令参考 本文所使用的 Ubuntu 系统版本是 Ubuntu 22.04 ! 一、需求说明 使用 Ubuntu 的过程中&#xff0c;屏…