(三

编程入门 行业动态 更新时间:2024-10-26 12:32:14

(三

(三

一个线程想发送信息到另一个线程, 最直接的方式是用全局变量, 但是全局变量难以管理, 而且一个线程希望等待信息的时候把自己挂起, 需要有一个方便的方案. 邮箱通信是操作系统中常用的一种通信机制.

如图所示, 很多操作系统(如RT-THREAD)邮箱其实也是个全局变量, 线程B往邮箱里发数据, 可以有多个线程接收, 甚至还能自己发自己收.

以RT-THREAD的邮箱为例, 只保留主要部分

struct pt_mailbox
{uint32_t            *msg_pool;          // 指向一块内存区域, 作为邮件的存储区uint16_t            size;               // 邮箱的大小, 单位 封, 一封邮件4字节, 即32位uint16_t            entry;              // 邮箱中当前邮件数量uint16_t            in_offset;          // 放入邮件的位置uint16_t            out_offset;         // 取出邮件的位置};


如图所示,
msg_pool指向了一块内存,
size=7, 这块内存可以放7封邮件,
entry=2,现在有两封邮件,
in_offset=3, 下一次发送邮件进来, 就放在第3个格子
out_offset=1, 下一次取邮件, 从第1个格子取

邮箱的初始化

int32_t pt_mb_init(pt_mailbox_t mb,const char  *name,void        *msgpool,uint32_t    size,uint8_t     flag)
{(void)name;(void)flag;/* init mailbox */mb->msg_pool   = msgpool;mb->size       = size;mb->entry      = 0;mb->in_offset  = 0;mb->out_offset = 0;return PT_EOK;
}

这里邮箱的初始化只保留主要部分, 就是对邮箱控制块里面的几个变量赋值为默认值.
用法:

    static char mb_pool[128];/* 初始化一个 mailbox */result = pt_mb_init(&mb,NULL,                     &mb_pool[0],                /* 邮箱用到的内存池是 mb_pool */sizeof(mb_pool) / 4,        /* 邮箱中的邮件数目,因为一封邮件占 4 字节 */NULL);         

发送邮件到邮箱

int32_t pt_mb_send(pt_mailbox_t mb, uint32_t value)
{if (mb->msg_pool == NULL){return -PT_ERROR;   //未初始化消息池}//邮件数量等于邮箱大小,满了不能再发送了,返回if (mb->entry == mb->size) {return -PT_EFULL;}// 放入邮件mb->msg_pool[mb->in_offset] = value;/* increase input offset */++ mb->in_offset;if (mb->in_offset >= mb->size)mb->in_offset = 0;/* increase message entry */mb->entry ++;return PT_EOK;
}

获取邮件

int32_t pt_mb_recv(pt_mailbox_t mb, uint32_t *value)
{if(PT_NULL == mb ){return -PT_ERROR;   //未初始化消息池}if (PT_NULL == mb->msg_pool){return -PT_ERROR;   //未初始化消息池}//没有邮件,直接返回if (mb->entry == 0){return -PT_EEMPTY;}// 读取邮件到传入的value中*value = mb->msg_pool[mb->out_offset];++ mb->out_offset;if (mb->out_offset >= mb->size){mb->out_offset = 0;}// 邮件数减一mb->entry --;return PT_EOK;
}

没有资源的时候挂起线程

有时线程需要在等待邮件的时候或者邮箱满无法发送的时候挂起线程, 基于Protothread如何实现呢?
只需要配合PT_WAIT_UNTIL即可.

#define PT_MB_SEND_WAIT_FOREVER(mb, value)  PT_WAIT_UNTIL((pt), PT_EOK == pt_mb_send(mb, value) )
#define PT_MB_RECV_WAIT_FOREVER(mb, addr)   PT_WAIT_UNTIL((pt), PT_EOK == pt_mb_recv(mb, (uint32_t *)addr) )

PT_WAIT_UNTIL会检查发送或接收邮件的结果, 如果没有发送或接收成功, 那么就让出CPU, 下一次进来时继续判断是否执行成功.

实例工程代码
.git

更多推荐

(三

本文发布于:2023-06-25 17:26:01,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/881958.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!