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

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

进程间的通信:

  消息队列共享内存信号灯

     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

相关文章

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Python如何精准判断某个进程是否在运行

《Python如何精准判断某个进程是否在运行》这篇文章主要为大家详细介绍了Python如何精准判断某个进程是否在运行,本文为大家整理了3种方法并进行了对比,有需要的小伙伴可以跟随小编一起学习一下... 目录一、为什么需要判断进程是否存在二、方法1:用psutil库(推荐)三、方法2:用os.system调用

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

SpringKafka错误处理(重试机制与死信队列)

《SpringKafka错误处理(重试机制与死信队列)》SpringKafka提供了全面的错误处理机制,通过灵活的重试策略和死信队列处理,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、Spring Kafka错误处理基础二、配置重试机制三、死信队列实现四、特定异常的处理策略五

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

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

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

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

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

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

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