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

本文主要是介绍嵌入式学习第二十四天!(进程间通信:消息队列、共享内存、信号灯),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

进程间的通信:

  消息队列共享内存信号灯

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

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

这篇关于嵌入式学习第二十四天!(进程间通信:消息队列、共享内存、信号灯)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/775226

相关文章

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

SpringIntegration消息路由之Router的条件路由与过滤功能

《SpringIntegration消息路由之Router的条件路由与过滤功能》本文详细介绍了Router的基础概念、条件路由实现、基于消息头的路由、动态路由与路由表、消息过滤与选择性路由以及错误处理... 目录引言一、Router基础概念二、条件路由实现三、基于消息头的路由四、动态路由与路由表五、消息过滤

Linux中的进程间通信之匿名管道解读

《Linux中的进程间通信之匿名管道解读》:本文主要介绍Linux中的进程间通信之匿名管道解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基本概念二、管道1、温故知新2、实现方式3、匿名管道(一)管道中的四种情况(二)管道的特性总结一、基本概念我们知道多

Linux进程终止的N种方式详解

《Linux进程终止的N种方式详解》进程终止是操作系统中,进程的一个重要阶段,他标志着进程生命周期的结束,下面小编为大家整理了一些常见的Linux进程终止方式,大家可以根据需求选择... 目录前言一、进程终止的概念二、进程终止的场景三、进程终止的实现3.1 程序退出码3.2 运行完毕结果正常3.3 运行完毕

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Windows命令之tasklist命令用法详解(Windows查看进程)

《Windows命令之tasklist命令用法详解(Windows查看进程)》tasklist命令显示本地计算机或远程计算机上当前正在运行的进程列表,命令结合筛选器一起使用,可以按照我们的需求进行过滤... 目录命令帮助1、基本使用2、执行原理2.1、tasklist命令无法使用3、筛选器3.1、根据PID

linux本机进程间通信之UDS详解

《linux本机进程间通信之UDS详解》文章介绍了Unix域套接字(UDS)的使用方法,这是一种在同一台主机上不同进程间通信的方式,UDS支持三种套接字类型:SOCK_STREAM、SOCK_DGRA... 目录基础概念本机进程间通信socket实现AF_INET数据收发示意图AF_Unix数据收发流程图A

Spring Boot整合消息队列RabbitMQ的实现示例

《SpringBoot整合消息队列RabbitMQ的实现示例》本文主要介绍了SpringBoot整合消息队列RabbitMQ的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录RabbitMQ 简介与安装1. RabbitMQ 简介2. RabbitMQ 安装Spring

springboot rocketmq配置生产者和消息者的步骤

《springbootrocketmq配置生产者和消息者的步骤》本文介绍了如何在SpringBoot中集成RocketMQ,包括添加依赖、配置application.yml、创建生产者和消费者,并展... 目录1. 添加依赖2. 配置application.yml3. 创建生产者4. 创建消费者5. 使用在

Python中多线程和多进程的基本用法详解

《Python中多线程和多进程的基本用法详解》这篇文章介绍了Python中多线程和多进程的相关知识,包括并发编程的优势,多线程和多进程的概念、适用场景、示例代码,线程池和进程池的使用,以及如何选择合适... 目录引言一、并发编程的主要优势二、python的多线程(Threading)1. 什么是多线程?2.