嵌入式学习第二十四天!(进程间通信:消息队列、共享内存、信号灯)

进程间的通信:

  消息队列共享内存信号灯

     1. IPC对象:内存文件

        1. ipcs:

            查看系统中的消息队列,共享内存、信号灯的信息

        2. ipcrm:

            删除消息队列、共享内存、信号灯

ipcrm -Q/-M/-S key
ipcrm -q/-m/-s 消息对立ID/共享内存ID/信号灯ID

1. 消息队列:

    1. 操作流程:

        创建消息队列 -> 发送消息 -> 接收消息

    2. 函数接口:

        1. ftok:
key_t ftok(const char *pathname, int proj_id);

          功能:根据pathname和proj_id生成一个key_t类型的key值,将来可以创建消息队列、共享内存、信号灯

          参数:

              pathename:文件路径

              proj_id:8位非0值

          返回值:

              成功返回key_t类型的IPC对象的key值
              失败返回-1 

        2. msgsnd:
int msgget(key_t key, int msgflg);

          功能:根据key值对象的IPC对象创建一个消息队列

          参数:

              key:IPC对象名字

              msgflg:IPC_CREAT    对象不存在就创建

                            IPC_EXCL       对象存在报错

                            IPC_CREAT | 0664

          返回值:

              成功返回消息队列ID
              失败返回-1

        3.  msgsnd:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

          功能:向消息队列中发送消息

          参数:

              msqid:消息队列的ID号

              msgp:发送消息空间的首地址

struct msgbuf
{
    int mtypes;    /* message type, must be > 0 */
    char mtext[1]  /* message data */
};

              msgz:发送消息内容的大小(不包含发送消息类型)

              msgflg:属性,默认位0

          返回值:

              成功返回0 
              失败返回-1 

        4. msgrcv:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

          功能:从消息队列中接收消息

          参数:

              msqid:消息队列的ID号

              msgp:存放接收到消息空间的首地址

              msgsz:最多接收消息的空间大小

              msgtype:想要接收消息的类型

              msgflg:属性,默认为0

          返回值:

              成功返回实际接收的字节数
              失败返回-1 

        5. msgctl:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

          功能:向消息队列发送一条cmd命令

          参数:

              msqid:消息队列的ID号

              cmd:IPC_RMID  删除消息队列

              buf:默认传NULL

        练习:

          利用消息队列实现clientA和clientB两个进程任务的全双工聊天功能

clientA.c

 #include "head.h"

key_t key;
int msgid = 0;
pthread_t atob;
pthread_t btoa;

struct msgbuf
{
	long mtype;
	char mtext[256];
};

void *thread_atob(void *arg)
{
	struct msgbuf sndmsg;
	while(1)
	{
		memset(&sndmsg, 0, sizeof(sndmsg));
		sndmsg.mtype = 100;
		gets(sndmsg.mtext);
		msgsnd(msgid, &sndmsg, sizeof(struct msgbuf)-sizeof(long), 0);
		
		if(strcmp(sndmsg.mtext, ".quit") == 0)
		{
			break;
		}
	}
	pthread_cancel(atob);
	return NULL;

}

void *thread_btoa(void *arg)
{
	struct msgbuf recmsg;
	while(1)
	{
		memset(&recmsg, 0, sizeof(recmsg));
		msgrcv(msgid, &recmsg, sizeof(recmsg)-sizeof(long), 200, 0);
		printf("RECV:%s\n", recmsg.mtext);

		if(strcmp(recmsg.mtext, ".quit") == 0)
		{
			break;
		}
	}
	pthread_cancel(btoa);
	return NULL;
}

int main(void)
{
	pthread_create(&atob, NULL, thread_atob, NULL);
	pthread_create(&btoa, NULL, thread_btoa, NULL);

	key = ftok(".", 'a');
	if(key == -1)
	{
		perror("fail to ftok");
		return -1;
	}

	msgid = msgget(key, IPC_CREAT | 0664);
	if(msgid == -1)
	{
		perror("fail to msgget");
		return -1;
	}

	pthread_join(atob, NULL);
	pthread_join(btoa, NULL);
		
	msgctl(msgid, IPC_RMID, NULL);

	return 0;
}

clientB.c

#include "head.h"

key_t key;
int msgid = 0;
pthread_t atob;
pthread_t btoa;

struct msgbuf
{
	long mtype;
	char mtext[256];
};


void *thread_btoa(void *arg)
{
	struct msgbuf sndmsg;
	while(1)
	{
		memset(&sndmsg, 0, sizeof(sndmsg));
		sndmsg.mtype = 200;
		gets(sndmsg.mtext);
		msgsnd(msgid, &sndmsg, sizeof(struct msgbuf)-sizeof(long), 0);
		
		if(strcmp(sndmsg.mtext, ".quit") == 0)
		{
			break;
		}
	}
	pthread_cancel(btoa);

	return NULL;
}

void *thread_atob(void *arg)
{
	struct msgbuf recmsg;
	while(1)
	{
		memset(&recmsg, 0, sizeof(recmsg));
		msgrcv(msgid, &recmsg, sizeof(recmsg)-sizeof(long), 100, 0);
		printf("RECV:%s\n", recmsg.mtext);
		
		if(strcmp(recmsg.mtext, ".quit") == 0)
		{
			break;
		}
	}
	pthread_cancel(atob);
	return NULL;
}

int main(void)
{
	pthread_create(&atob, NULL, thread_atob, NULL);
	pthread_create(&btoa, NULL, thread_btoa, NULL);
	
	key = ftok(".", 'a');
	if(key == -1)
	{
		perror("fail to ftok");
		return -1;
	}

	msgid = msgget(key, IPC_CREAT | 0664);
	if(msgid == -1)
	{
		perror("fail to msgget");
		return -1;
	}

	pthread_join(atob, NULL);
	pthread_join(btoa, NULL);
	
	msgctl(msgid, IPC_RMID, NULL);

	return 0;
}

2. 共享内存:

  进程间通信最高效的形式

  1. 操作方式:

        创建共享内存  ->  映射到共享内存中  ->  共享内存操作  ->  解除映射  ->  删除共享内存

  2. 函数接口:

        1. ftok:
key_t ftok(const char *pathname, int proj_id);

          功能:根据pathname和proj_id生成一个key_t类型的key值,将来可以创建消息队列、共享内存、信号灯

          参数:

              pathename:文件路径

              proj_id:8位非0值

          返回值:

              成功返回key_t类型的IPC对象的key值
              失败返回-1 

        2. shmget:
int shmget(key_t key, size_t size, int shmflg);

          功能:创建一个共享内存

          参数:

              key:IPC对象名称

              size:共享内存的大小

              shmflg:

                    IPC_CREAT

                    IPC_EXCL

          返回值:

              成功返回共享内存ID
              失败返回-1 

        3. shmat
void *shmat(int shmid, const void *shmaddr, int shmflg);

          功能:将一个地址映射到共享内存中

          参数:

              shmid:共享内存ID号

              shmaddr:

                    NULL:让系统选择一个合适的地址映射

                    不为NULL:shmflg设定SHM_RND选择离给定地址最近的能够映射的地址进行映射,否则传递地址为4K的整数倍

        4. shmdt:
int shmdt(const void *shmaddr);

          功能:解除映射

          参数:

              shmaddr:映射的地址

          返回值:

              成功返回0 
              失败返回-1 

        5. shmctl:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

          功能:向共享内存发送命令

          参数:

              shmid:共享内存ID号

              cmd:IPC_RMID 删除共享内存

              buf:NULL

          返回值:

              成功返回0 
              失败返回-1

        练习:

              编写2个进程任务,write.c负责从终端接收字符串写入共享内存中,read.c负责将共享内存中的数据打印在终端

write.c

#include "head.h"

int main(void)
{
	key_t key;
	int shmid;
	char *pshm = NULL;
	
	key = ftok(".", 'a');
	if(key == -1)
	{
		perror("fail to ftok");
		return -1;
	}

	shmid = shmget(key, 4096, IPC_CREAT | 0664);
	if(shmid == -1)
	{
		perror("fail to shmget");
		return -1;
	}
	
	pshm = (char *)shmat(shmid, NULL, 0);
	if(pshm == NULL)
	{
		perror("fail to shmat");
		return -1;
	}
	
	while(1)
	{
		gets(pshm);
		if(!strcmp(pshm, ".quit"))
		{
			shmdt(pshm);
			break;
		}
	}
	shmctl(shmid, IPC_RMID, NULL);

	return 0;
}
#include "head.h"

int main(void)
{
	key_t key;
	int shmid;
	char *pshm = NULL;
	char *ptmp = NULL;

	key = ftok(".", 'a');
	if(key == -1)
	{
		perror("fail to ftok");
		return -1;
	}

	shmid = shmget(key, 4096, IPC_CREAT | 0664);
	if(shmid == -1)
	{
		perror("fail to shmget");
		return -1;
	}
	
	pshm = shmat(shmid, NULL, 0);
	ptmp = malloc(4096);	
	
	strcpy(ptmp, pshm);

	while(1)
	{
		if (strcmp(pshm, ptmp) == 0)
		{
			continue;
		}
		else
		{
            printf("%s\n", pshm);
            strcpy(ptmp, pshm);
        }

		if(!strcmp(pshm, ".quit"))
		{
			free(ptmp);
			shmdt(pshm);
			break;
		}
	}

	shmctl(shmid, IPC_RMID, NULL);

	return 0;
}

        在这里使用了一个ptmp和原来的pshm比较,从而实现了一个从终端写一个,接收一个,其实应该使用信号灯实现,但是在这里还没有学,所以先暂时使用这个来实现。如果不加判断的话,终端输出的结果如下所示:

        终端会一直持续打印共享内存中的数据,继而需要用到信号灯来实现,写一条,只接收一条

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

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

相关文章

linux安装部署

jdk&tomcat安装 1.上传jdk、tomcat安装包 2.解压两个工具包 #解压tar -zxvf apache-tomcat-8.5.20.tar.gz#解压jdktar -zxvf jdk-8u151-linux-x64.tar.gz 3.配置并且测试jdk安装 #配置环境变量vim /etc/profile​#java environmentexport JAVA_HOME/soft/jdk1.8.0_151exp…

Whisper实现语音识别转文本

#教程 主要参考开源免费离线语音识别神器whisper如何安装, OpenAI开源模型Whisper——音频转文字 Whisper是一个开源的自动语音识别系统,它在网络上收集了680,000小时的多语种和多任务监督数据进行训练,使得它可以将多种语言的音频转文字。…

【学位论文】上海交通大学 研究生学位论文 本地保存

上海交大研究生学位论文网:http://thesis.lib.sjtu.edu.cn/ (只能校内访问或SJTU VPN访问) 如果希望下载论文,需要参考:https://github.com/olixu/SJTU_Thesis_Crawler 安装过程 安装过程的几个坑: &a…

【Java开发】Java实现调用微信机器人,发送企业微信通知

请直接看原文: 【Java开发】Java实现调用微信机器人,发送企业微信通知_java 企业微信推送机器人消息-CSDN博客 ------------------------------------------------------------------------------------------------------------------------------- 企业微信机器…

无需安装!7款一键在线UI设计利器

制作完原型后,需要优化界面。此时是UI设计师的任务。UI设计软件对设计师来说非常重要。UI设计工具的使用是否直接影响到最终结果的质量,所以有人会问:UI界面设计使用什么软件?这里有一些UI设计师和对UI设计感兴趣的朋友列出了五款好用免费的U…

Unity 动态加载音频和音效

想要加载音效和音频需要两个组件: 听: 播: 一收一发 在层级中,右键创建 音频源 ,放入物体的子物体中。 播放 方式一 拖动需要播放的音频文件到,音频源组件中。 using System.Collections; using Syst…

java BIO

目录 Java BIO基本介绍 Java BIO工作机制 传统的BIO编程实例回顾 1、BIO模式下发送和接收消息 2、BIO模式下多发和多收消息 3、BIO模式下接收多个客户端 伪异步I/O编程 基于BIO形式下的文件上传 Java BIO模式下的端口转发思想 Java BIO基本介绍 Java BIO就是传统的jav…

Pytorch学习 day03(Tensorboard)

Tensorboard Tensorboard能够可视化loss的变化过程,便于我们查看模型的训练状态,也能查看模型当前的输入和输出结果 在Pycharm中,可以通过按住ctrl,并左键点击某个库来进入源文件查看该库的使用方法 SummaryWriter是用来向log_di…

C语言:指针(二)

目录 1.数组名的理解2.使用指针访问数组3.一维数组传参的本质4.二级指针5.指针数组6.字符指针变量7.数组指针变量8.二维数组传参的本质9.函数指针变量10.函数指针数组11.回调函数12.qsort函数13.使用回调函数模拟实现qsort函数 1.数组名的理解 int main() {int arr[] { 1,2,3…

上帝视角看GPU(5):图形流水线里的不可编程单元

【GPU】图形流水线基础【GPU】逻辑上的模块划分【GPU】部署到硬件【GPU】完整的软件栈 前几期我们过了一遍GPU的软硬栈。这次我们将深入GPU图形流水线的一些细节,看看那些不可编程的模块是怎么工作的。 对于GPU的图形流水线来说,最核心最重要的一个组件就…

通过人工智能增强的对话建立有意义的联系

人工智能如何重塑我们的交流?2024年最新对话AI趋势 在技术和人类互动比以往任何时候都更加复杂地交织在一起的时代,人工智能增强的对话已成为建立有意义的联系的关键要素。 这种转变不仅关乎效率,还关乎效率。 这是为了丰富沟通的结构。 在这…

MATLAB--pie函数绘制复杂分类饼图(2)--附案例代码

MATLAB–pie函数绘制复杂分类数据的饼状图 目录 MATLAB--pie函数绘制复杂分类数据的饼状图摘要1. 问题描述2. 具体步骤:3. 绘制结果4. 小结 摘要 在数据可视化中,饼状图是一种常用的展示分类数据的方式。之前,文章介绍了使用MATLAB绘制饼状图…

Vue中的计算属性和方法有什么区别?

Vue.js是一款流行的JavaScript前端框架,提供了丰富的功能和便捷的开发方式。在Vue中,计算属性和方法是常用的两种方式来处理数据和逻辑。但它们之间存在一些区别,本文将详细介绍Vue中计算属性和方法的区别,并通过示例代码加深理解…

654.最大二叉树

这段Java代码实现了一个名为Solution的类,其中包含两个方法:constructMaximumBinaryTree()和constructMaximumBinaryTree1(),目的是从给定的整数数组nums中构建出一个最大二叉树。以下是详细的注释说明: class Solution {// 主方…

GitHub Copilot extension activation error: ‘No access to GitHub Copilot found‘

好不容易学生认证通过了,打开vscode用copilot结果一直报这个错误。我的原因是:还未给copilot授权, 通过了学生认证后要进入这里进行授权:

MCU设计--M3内核整体功能说明

整体架构 内核特性 CM3内核支持3级流水哈佛结构 :数据和指令隔离Blanked SP :两个堆栈,一个堆栈只允许系统操作,另一个堆栈开放给用户。Handler and Thread modes低延迟中断进入和退出支持非对齐操作嵌套中断向量 最大支持1-240个外部中断可设置3-8的优先级可动态配置优先级…

一文了解什么是园区网以及如何部署园区网

目录 一、局域网分类 二、园区网的业务部署内容 1、构建高可靠可冗余网络 2、组播业务的快速开展 3、语音业务的部署 4、网络安全的部署 5、网络管理和维护的应用 一、局域网分类 (1)园区网: 目的:让各种服务器提供服务 …

mysql学习笔记3——授权操作

利用select查询数据库数据时,可以在后面加上参数 意为限制显示条数 对数据库进行远程操作时,为了避免不同用户操作混乱,要设置不同用户的权限,可以使用 具体格式为 其中*代表任意均可 ,这里用户创建采用与授权同时进…

【OJ】求和与计算日期

文章目录 1. 前言2. JZ64 求123...n2.1 题目分析2.2 代码 3. HJ73 计算日期到天数转换3.1 题目分析3.2 代码 4. KY222 打印日期4.1 题目分析4.2 代码 1. 前言 下面两个题目均来自牛客,使用的编程语言是c,分享个人的一些思路和代码。 2. JZ64 求123…n …

北京大学发布,将试错引入大模型代理学习!

引言:探索语言智能的新边界 在人工智能的发展历程中,语言智能始终是一个核心的研究领域。随着大语言模型(LLM)的兴起,我们对语言智能的理解和应用已经迈入了一个新的阶段。这些模型不仅能够理解和生成自然语言&#x…