邮箱

邮箱基本知识

  • 邮箱中的每一封邮件只能容纳固定的 4 字节内容
  • 非阻塞方式的邮件发送过程能够安全的应用于中断服务中,是线程、中断服务、定时器向线程发送消息的有效手段
  • 当一个线程向邮箱发送邮件时,如果邮箱没满,将把邮件复制到邮箱中,如果满了,要么阻塞等待,要么超时。
  • 邮件的接收,没有邮件就要阻塞等待或超时等待
RT_EFULL     //邮箱满了
RT_ETIMEOUT //等待超时

邮箱结构

struct rt_mailbox
{struct rt_ipc_object parent;rt_uint32_t* msg_pool;                /* 邮箱缓冲区的开始地址 */rt_uint16_t size;                     /* 邮箱缓冲区的大小     */rt_uint16_t entry;                    /* 邮箱中邮件的数目     */rt_uint16_t in_offset, out_offset;    /* 邮箱缓冲的进出指针   */rt_list_t suspend_sender_thread;      /* 发送线程的挂起等待队列 */
};
typedef struct rt_mailbox* rt_mailbox_t;

邮箱函数

动态创建邮箱


rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag);
//邮箱标志,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO
rt_err_t rt_mb_delete (rt_mailbox_t mb);

RT_IPC_FLAG_FIFO 实时方式,push_head
RT_IPC_FLAG_PRIO 非实时方式 push_tail

静态方式邮箱

  rt_err_t rt_mb_init(rt_mailbox_t mb,const char* name,void* msgpool,rt_size_t size,rt_uint8_t flag)rt_err_t rt_mb_detach(rt_mailbox_t mb);

邮件发送

线程或者中断服务程序可以通过邮箱给其他线程发送邮件

//非阻塞方式发送
rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value);
//等待发送
rt_err_t rt_mb_send_wait (rt_mailbox_t mb,rt_uint32_t value,rt_int32_t timeout);//发送紧急事件
rt_err_t rt_mb_urgent (rt_mailbox_t mb, rt_ubase_t value);

邮件接收

rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout);

传输超过4字节的邮件

在线程间传递比较大的消息时,可以把指向一个缓冲区的指针作为邮件发送到邮箱中,即邮箱也可以传递指针
使用示例

#include <rtthread.h>#define THREAD_PRIORITY      10
#define THREAD_TIMESLICE     5/* 邮箱控制块 */
static struct rt_mailbox mb;
/* 用于放邮件的内存池 */
static char mb_pool[128];static char mb_str1[] = "I'm a mail!";
static char mb_str2[] = "this is another mail!";
static char mb_str3[] = "over";ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;/* 线程 1 入口 */
static void thread1_entry(void *parameter)
{char *str;while (1){rt_kprintf("thread1: try to recv a mail\n");/* 从邮箱中收取邮件 */if (rt_mb_recv(&mb, (rt_uint32_t *)&str, RT_WAITING_FOREVER) == RT_EOK){rt_kprintf("thread1: get a mail from mailbox, the content:%s\n", str);if (str == mb_str3)break;/* 延时 100ms */rt_thread_mdelay(100);}}/* 执行邮箱对象脱离 */rt_mb_detach(&mb);
}ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;/* 线程 2 入口 */
static void thread2_entry(void *parameter)
{rt_uint8_t count;count = 0;while (count < 10){count ++;if (count & 0x1){/* 发送 mb_str1 地址到邮箱中 */rt_mb_send(&mb, (rt_uint32_t)&mb_str1);}else{/* 发送 mb_str2 地址到邮箱中 */rt_mb_send(&mb, (rt_uint32_t)&mb_str2);}/* 延时 200ms */rt_thread_mdelay(200);}/* 发送邮件告诉线程 1,线程 2 已经运行结束 */rt_mb_send(&mb, (rt_uint32_t)&mb_str3);
}int mailbox_sample(void)
{rt_err_t result;/* 初始化一个 mailbox */result = rt_mb_init(&mb,"mbt",                      /* 名称是 mbt */&mb_pool[0],                /* 邮箱用到的内存池是 mb_pool */sizeof(mb_pool) / 4,        /* 邮箱中的邮件数目,因为一封邮件占 4 字节 */RT_IPC_FLAG_FIFO);          /* 采用 FIFO 方式进行线程等待 */if (result != RT_EOK){rt_kprintf("init mailbox failed.\n");return -1;}rt_thread_init(&thread1,"thread1",thread1_entry,RT_NULL,&thread1_stack[0],sizeof(thread1_stack),THREAD_PRIORITY, THREAD_TIMESLICE);rt_thread_startup(&thread1);rt_thread_init(&thread2,"thread2",thread2_entry,RT_NULL,&thread2_stack[0],sizeof(thread2_stack),THREAD_PRIORITY, THREAD_TIMESLICE);rt_thread_startup(&thread2);return 0;
}/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(mailbox_sample, mailbox sample);

消息队列

基本知识

  • 消息队列能够接收来自线程或中断服务例程中不固定长度的消息,并把消息缓存在自己的内存空间中
  • 先进先出原则 (FIFO)

队列结构

struct rt_messagequeue
{struct rt_ipc_object parent;void* msg_pool;                     /* 指向存放消息的缓冲区的指针 */rt_uint16_t msg_size;               /* 每个消息的长度 */rt_uint16_t max_msgs;               /* 最大能够容纳的消息数 */rt_uint16_t entry;                  /* 队列中已有的消息数 */void* msg_queue_head;               /* 消息链表头 */void* msg_queue_tail;               /* 消息链表尾 */void* msg_queue_free;               /* 空闲消息链表 */rt_list_t suspend_sender_thread;    /* 发送线程的挂起等待队列 */
};
typedef struct rt_messagequeue* rt_mq_t;

消息队列使用的函数

动态创建和删除消息队列

rt_mq_t rt_mq_create(const char* name,rt_size_t msg_size,//消息队列中一条消息的最大长度,单位字节rt_size_t max_msgs, //消息队列的最大个数rt_uint8_t flag);//实时消息:RT_IPC_FLAG_FIFO 或 非实时 RT_IPC_FLAG_PRIOrt_err_t rt_mq_delete(rt_mq_t mq);

静态创建和删除

rt_err_t rt_mq_init(rt_mq_t mq, const char* name,void *msgpool, rt_size_t msg_size,rt_size_t pool_size, rt_uint8_t flag);rt_err_t rt_mq_detach(rt_mq_t mq);

发送消息

//非阻塞方式发送
rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size);
//等待方式发送
rt_err_t rt_mq_send_wait(rt_mq_t     mq,const void *buffer,rt_size_t   size,rt_int32_t  timeout);
//发送紧急消息
rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size);

接收消息

rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer,rt_size_t size, rt_int32_t timeout);

使用场合

  • 中断服务例程不能接收消息
  • 消息队列可以应用于发送不定长消息的场合,包括线程与线程间的消息交换,以及中断服务例程中给线程发送消息

使用示例

#include <rtthread.h>/* 消息队列控制块 */
static struct rt_messagequeue mq;
/* 消息队列中用到的放置消息的内存池 */
static rt_uint8_t msg_pool[2048];ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
/* 线程 1 入口函数 */
static void thread1_entry(void *parameter)
{char buf = 0;rt_uint8_t cnt = 0;while (1){/* 从消息队列中接收消息 */if (rt_mq_recv(&mq, &buf, sizeof(buf), RT_WAITING_FOREVER) == RT_EOK){rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", buf);if (cnt == 19){break;}}/* 延时 50ms */cnt++;rt_thread_mdelay(50);}rt_kprintf("thread1: detach mq \n");rt_mq_detach(&mq);
}ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
/* 线程 2 入口 */
static void thread2_entry(void *parameter)
{int result;char buf = 'A';rt_uint8_t cnt = 0;while (1){if (cnt == 8){/* 发送紧急消息到消息队列中 */result = rt_mq_urgent(&mq, &buf, 1);if (result != RT_EOK){rt_kprintf("rt_mq_urgent ERR\n");}else{rt_kprintf("thread2: send urgent message - %c\n", buf);}}else if (cnt>= 20)/* 发送 20 次消息之后退出 */{rt_kprintf("message queue stop send, thread2 quit\n");break;}else{/* 发送消息到消息队列中 */result = rt_mq_send(&mq, &buf, 1);if (result != RT_EOK){rt_kprintf("rt_mq_send ERR\n");}rt_kprintf("thread2: send message - %c\n", buf);}buf++;cnt++;/* 延时 5ms */rt_thread_mdelay(5);}
}/* 消息队列示例的初始化 */
int msgq_sample(void)
{rt_err_t result;/* 初始化消息队列 */result = rt_mq_init(&mq,"mqt",&msg_pool[0],             /* 内存池指向 msg_pool */1,                          /* 每个消息的大小是 1 字节 */sizeof(msg_pool),        /* 内存池的大小是 msg_pool 的大小 */RT_IPC_FLAG_PRIO);       /* 如果有多个线程等待,优先级大小的方法分配消息 */if (result != RT_EOK){rt_kprintf("init message queue failed.\n");return -1;}rt_thread_init(&thread1,"thread1",thread1_entry,RT_NULL,&thread1_stack[0],sizeof(thread1_stack), 25, 5);rt_thread_startup(&thread1);rt_thread_init(&thread2,"thread2",thread2_entry,RT_NULL,&thread2_stack[0],sizeof(thread2_stack), 25, 5);rt_thread_startup(&thread2);return 0;
}/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(msgq_sample, msgq sample);

信号

基本知识

  • 信号(又称为软中断信号)
  • 应用程序能够使用的信号为 SIGUSR1(10)和 SIGUSR2(12)
  • 调用 rt_thread_kill() 发送软中断信号。

收到信号的线程对各种信号有不同的处理方法

  1. 是类似中断的处理程序,对于需要处理的信号,线程可以指定处理函数,由该函数来处理。

  2. 忽略某个信号,对该信号不做任何处理,就像未发生过一样。

  3. 对该信号的处理保留系统的默认值。

  • 当信号被传递给线程 1 时,如果它正处于挂起状态,那会把状态改为就绪状态去处理对应的信号。如果它正处于运行状态,那么会在它当前的线程栈基础上建立新栈帧空间去处理对应的信号,需要注意的是使用的线程栈大小也会相应增加

信号的相关函数

安装信号

rt_sighandler_t rt_signal_install(
int signo, //信号值(只有 SIGUSR1 和 SIGUSR2 是开放给用户使用的
rt_sighandler_t[] handler);

处理函数

void thread1_signal_handler(int sig)
  • 默认的处理函数_signal_default_handler()。

阻塞信号

信号阻塞,也可以理解为屏蔽信号。如果该信号被阻塞,则该信号将不会递达给安装此信号的线程,也不会引发软中断处理

void rt_signal_mask(int signo);

解除信号阻塞

线程中可以安装好几个信号,使用此函数可以对其中一些信号给予 “关注”,那么发送这些信号都会引发该线程的软中断

void rt_signal_unmask(int signo);

发送信号

int rt_thread_kill(rt_thread_t tid, int sig);

等待信号

等待 set 信号的到来,如果没有等到这个信号,则将线程挂起,直到等到这个信号或者等待时间超过指定的超时时间 timeout

使用示例

#include <rtthread.h>#define THREAD_PRIORITY         25
#define THREAD_STACK_SIZE       512
#define THREAD_TIMESLICE        5static rt_thread_t tid1 = RT_NULL;/* 线程 1 的信号处理函数 */
void thread1_signal_handler(int sig)
{rt_kprintf("thread1 received signal %d\n", sig);
}/* 线程 1 的入口函数 */
static void thread1_entry(void *parameter)
{int cnt = 0;/* 安装信号 */rt_signal_install(SIGUSR1, thread1_signal_handler);rt_signal_unmask(SIGUSR1);/* 运行 10 次 */while (cnt < 10){/* 线程 1 采用低优先级运行,一直打印计数值 */rt_kprintf("thread1 count : %d\n", cnt);cnt++;rt_thread_mdelay(100);}
}/* 信号示例的初始化 */
int signal_sample(void)
{/* 创建线程 1 */tid1 = rt_thread_create("thread1",thread1_entry, RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY, THREAD_TIMESLICE);if (tid1 != RT_NULL)rt_thread_startup(tid1);rt_thread_mdelay(300);/* 发送信号 SIGUSR1 给线程 1 */rt_thread_kill(tid1, SIGUSR1);return 0;
}/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(signal_sample, signal sample);

RTT学习笔记5-线程间的通讯相关推荐

  1. RT-Thread学习笔记六——线程间通讯(信号量的使用)

    目录 1.概念 1.1  二值型信号量 1.2  计数型信号量 2.信号量的创建(API) 2.1动态信号量创建 2.2动态信号量的删除 2.3静态信号量的创建 2.4静态信号量的删除 3.信号量的获 ...

  2. PyQt5学习笔记13----pyqt线程间通信

    信号(singal)与槽(slot)用于对象相互通信,信号:当某个对象的某个事件发生时,触发一个信号,槽:响应指定信号的所做的反应,其实信号槽类似于.NET里面的委托.事件,比如Repeater控件类 ...

  3. java学习笔记14--多线程编程基础1

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ...

  4. java线程间的通讯

    主要通过wait()和notify()方法进行线程间的通讯 class Product extends Thread{String name;float price;boolean flag = fa ...

  5. java学习笔记15--多线程编程基础2

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡 ...

  6. java 线程类 通信_Java 中利用管道实现线程间的通讯

    在Java 语言中,提供了各种各样的输入输出流(stream),使我们能够很方便的对数据进行操作,其中,管道(pipe)流是一种特殊的流,用于在不同线程(threads)间直接传送数据.一个线程发送数 ...

  7. 【java笔记】线程间通信(2):生产者和消费者案例分析

    [java笔记]线程间通信(1):等待唤醒机制_m0_52043808的博客-CSDN博客 类: 资源类:包子类:皮,馅,有无 生产者: 包子铺类(线程类)(继承Thread) 设置线程任务(run) ...

  8. java中的僵死进程_Java中线程间怎么通讯?什么叫僵死线程?

    <尸家保镖> <猛鬼出千> <不死心灵> <大家发财> <灵幻少女> <九天玄女> <僵尸至尊> <湘西尸王& ...

  9. java基础—线程间的通讯 生产者与消费者

    线程间的的通讯  生产者与消费者 public class TestDemos3 {public static void main(String[] args){Res r = new Res();I ...

最新文章

  1. 邮件里面的图怎么复制出来_如何从INS批量导出邮件开发新的客户,推广产品和找reviewer【小技巧】...
  2. 大型WEB架构概况(笔记整理)一
  3. IIS6注册.net4.0
  4. 信息学奥赛一本通(1123:图像相似度)
  5. Java面向对象16种原则
  6. C语言学习笔记---浮点函数modf()和fmod()
  7. 接口与事件之图形界面的认证登录
  8. 《访问Mat图像中每个像素的值》)
  9. 使用 rtcwake 定时唤醒休眠的linux
  10. Linux下的IPC机制
  11. BUUCTF笔记之Misc系列部分WriteUp(一)
  12. 嵌入式 CIF/4CIF/QCIF/D1分辨率
  13. 【第86期】CPU 空闲时在干嘛?
  14. 【基于canvas实现雪花飘落】
  15. 小米5 miui9 android8,小米5升级MIUI9速度对比MIUI8:开机就快10秒
  16. React中Mpegts播放器的使用
  17. 一文看懂智慧城市,解码25万亿大市场的机遇与格局
  18. verilog之分频大全
  19. 持续集成与持续部署(五)01-TravisCI——使用简介-Travis CI 只支持 Github,提供的是持续集成服务 配置项目的.travis.yml文件
  20. NR PRACH(一)Preamble的确定

热门文章

  1. navicat连接mysql报错ssh_Navicat 连接SSH方式连接mysql报错 ssh:expected key exchange group packet...
  2. linux ntfs 密码,linux 加载ntfs和fat32分区
  3. 7.请解释泛型list集合的长度为什么动态的?_Java面试题集合篇一
  4. java判断两个时间区间是否有重合
  5. 使用哈工大LTP做自然语言处理任务基础demo
  6. Python编辑距离
  7. pandas apply()函数传参,与解决TypeError: xxxx() takes 2 positional arguments but 3 were given报错
  8. 嵌入网站的挖矿代码——CoinImp
  9. echart 饼图每一块间隙_排队3h?为了火遍tou音的芝士水果饼,值得吗?!
  10. java工商银行项目_ChaosBlade 在工商银行混沌工程体系中的应用实践