System V IPC对象 - 消息队列
- 消息队列是System VIPC对象的一种
- 消息队列由消息队列ID来唯一标识
- 消息队列就是一个消息的列表。用户可以在消息队列中
- 添加消息、读取消息等
- 消息队列可以按照类型来发送/接收消息
消息队列分不同的消息队列来存放消息,多个进程读写同一个消息队列,对方想和一个进程通信的话,只需发该进程对应类型的消息,对方想和我通信的话,只需发我所对应的类型的消息。
- 消息队列属于一个异步中间件
异步概念 异步处理不用阻塞当前线程来等待处理完成,而是允许后续操作,直至其它线程将处理完成,并回调通知此线程。必须强调一个基础逻辑,异步是一种设计理念异步操作不等于多线程,MQ中间件,或者消息广播,这些是可以实现异步处理的方式。同步处理和异步处理相对,需要实时处理并响应,一旦超过时间会结束会话,在该过程中调用方一直在等待响应方处理完成并返回。同步类似电话沟通,需要实时对话,异步则类似短信交流,发送消息之后无需保持等待状态。
消息队列结构:

消息队列使用步骤:
- 打开/创建消息队列msget
IPC_CREAT 如果消息队列不存在就创建一个消息队列并绑定key值,如果该key值已经绑定了一个消息队列就返回该消息队列id。
1 |
|
打开/创建消息队列示例:
1 | int main() |
- 向消息队列发送消息msgsnd
1 |
|
消息格式的第一个成员必须是long类型用来表示消息的类型:
1 | struct process1_msg |
向消息队列发送消息示例:
消息队列是如何做到多个进程往消息队列发送和接收不同类型的消息的?(类似于订阅和发布架构)
1.向一个消息队列发送消息都要指定消息类型,其他进程在从这个消息队列接收消息的时候就是通过消息类型识别是否是自己想要的消息。
2.消息队列中会给每个不同类型的消息创建一个链表,同类型的消息挂载同一个链表,这些子链表又组成一个父链表。
3.消息队列在接收(取)消息的时候,首先遍历父链表找到要取的消息类型子链表。
消息链表结构原型:
1
2
3
4
5
6
7
8
9
10
11
12 struct msg_link1
{
int type; // 消息类型
int length; // 每个消息长度
int *msg_read; // 读取消息的指针,下次从这里读消息
int *msg_wirte; // 写消息的指针,下次从这里写消息
struct msg
{
int *pnext; // 下一个消息的首地址,msg_wirte->pnext = &new_msg; new_msg->pnext = msg_read;
char *mdata; // 消息的内容指针
}
};4.消息的类型只有一份,只需要把消息的正文按fifo顺序挂载, msgsnd(msgid, &buf, LEN, O); // 发送的消息类型长度不包含消息的类型长度
PS:上面讲的子链表用数组就能满足要求了,因为每个节点的大小一样读写逻辑上也是顺序的
从消息队列发送消息示例:
1 | typedef struct // 定义一个消息类型 |
- 从消息队列接收消息msgrcv
msgtype指定接收的消息类型,就是发送时消息结构里面的消息类型成员,0代表接收最近时间接收的消息(说明消息队列结构体中有一个保存最后发送消息类型用的变量),-1代表接收最高优先级进程发来的消息(不常用)
1 |
|
从消息队列接收消息示例:
1 | typedef struct |
- 控制消息队列msgctl
消息队列在创建的时候并没有指定大小,用的是系统默认大小参数
第一个使用消息队列的进程负责创建消息队列并把key和新创建的消息队列id绑定,其他的调用消息队列创建函数的进程只是通过key获得了消息队列的id。其中的详细过程参考共享内存章节。
IPC_STAT :获取消息队列属性
IPC_SET :设置消息队列属性
IPC_RMID:删除一个消息队列,立刻执行删除操作,再对消息队列进行发送接收会提示出错
1 |
|
示例1:
要求:两个进程通过消息队列轮流将键盘输入的字符串发送给对方,接收并打印对方发送的消息
1 |
|
运行结果:

查看系统中已经创建的消息队列:

示例2:
要求:两个进程通过消息队列将键盘输入的字符串实时发送给对方,实时接收并打印对方发送的消息,进程中采用多线程方式。
1 |
|
运行结果:

小结:
1.上面的示例2如果要用RTOS+MCU实现的话:需要创建四个线程,两个消息队列。一个线程1从串口1获得数据并向消息队列1发送数据,线程2从消息队列1接收并打印到串口2;线程3从串口2获得数据并向消息队列2发送数据,线程4从消息队列2接收并打印到串口1。
1.RTOS的消息队列只能把所接收的消息串联成一个链表也就是一个消息队列只能用来存放一个类型的消息,没有像linux这样可以对消息进行分类挂载到多个子链表。
3.不过MCU一般的应用场景是线程1从串口1接收数据到消息队列1,线程2接收接收队列1中的数据并解析得到应答数据然后将应答的数据发送到消息队列2,线程3发送消息队列2中的数据到串口1。












