一互斥量:是信号量的一种,用于共享资源的排他性使用,以锁的形式存在,初始化时为可用,不能在中断中使用,可能导致优先级翻转。
二 事件:创建、删除、初始化、解绑、等待、发送。可以一对多多对的,发送一个事件,所有等待的都有效。可以进行逻辑“与”“或”,不能进行累加;而信号量可以累加但不能进行与或;
三 邮箱:创建、删除、初始化、解绑、发送、接收。用于线程间多数据的传递,类似管道,邮箱单次发送默认4字节(一个指针的大小),邮箱开销小比信号量和消息队列效率高。如果是数据,结构体可以采用以下方法
数组:邮箱的地址为数组的开始地址;邮箱的容量为sizeof(数组)/4
结构体:
struct msg
{
rt_uint8_t *data_ptr;
rt_uint32_t data_size;
};
对于这样一个消息结构体,其中包含了指向数据的指针data_ptr和数据块长度的变量data_size。当一个线程需要把这个消息发送给另外一个线程时,可以采用如下的操作:
struct msg* msg_ptr;
msg_ptr = (struct msg*)rt_malloc(sizeof(struct msg));
msg_ptr->data_ptr = ...; /* 指向相应的数据块地址*/
msg_ptr->data_size = len; /* 数据块的长度*/
/* 发送这个消息指针给mb邮箱*/
rt_mb_send(mb, (rt_uint32_t)msg_ptr);
而在接收线程中,因为收取过来的是指针,而msg_ptr是一个新分配出来的内存块,所以在接收线程处理完毕后,需要释放相应的内存块:
struct msg* msg_ptr; if (rt_mb_recv(mb, (rt_uint32_t*)&msg_ptr) == RT_EOK) { /* 在接收线程处理完毕后,需要释放相应的内存块*/ rt_free(msg_ptr); }
消息队列:也是线程或中断与线程间通讯的一种异步通讯手段,且不限长度(只能发送4字节的限制,如果长度为4则消息队列退化成消息邮箱)。每个队列包含若干消息框,每个消息框存放一条消息。缓存池地址,消息框数及每个消息框大小,当前已有的消息数,头和尾。
除了创建、删除、初始化、解绑、收、发外还有一个紧急发送,将队列放到消息队列的头而不是尾部。注意下面例子:消息队列因为是数据内容的直接复制(深拷贝),所以用局部变量即可
这样也就免去动态内存分配的烦恼了(也就不用担心,接收线程在接收到消息时,消息内存空间已经被释放)
void send_op(void *data, rt_size_t length)
{
struct msg msg_ptr;
msg_ptr.data_ptr = data; /* 指向相应的数据块地址 */
msg_ptr.data_size = length; /* 数据块的长度 */
/* 发送这个消息指针给mq消息队列 */
rt_mq_send(mq, (void*)&msg_ptr, sizeof(struct msg));
}
void message_handler()
{
struct msg msg_ptr; /* 用于放置消息的局部变量 */
/* 从消息队列中接收消息到msg_ptr中 */
if (rt_mq_recv(mq, (void*)&msg_ptr, sizeof(struct msg)) == RT_EOK)
{
/* 成功接收到消息,进行相应的数据处理 */
}
}
线程A发消息队列给线程B,并希望得到B的收到确认信息,此时确认信息可以用信号量(只是通知收到了)或者用邮箱(还包括状态值信息)