目录
一 RT-Thread 信号量
二 RT-Thread 互斥量
三 RT-Thread 事件标志组
四 RT-Thread 邮箱
五 RT-Thread 消息队列
1. 信号量相关函数
创建信号量 | /** @param name:信号量名称 * @param value:信号量初始值 * @param flag:信号量标志,可取RT_IPC_FLAG_FIFO或者RT_IPC_FLAG_PRIO rt_sem_t rt_sem_create (const char* name,rt_uint32_t value,rt_uint8_t flag); |
删除信号量 | /** @param sem:rt_sem_create创建处理的信号量对象 rt_err_t rt_sem_delete (rt_sem_t sem); |
初始化静态信号量 | /** @param sem:信号量对象的句柄 * @param name:信号量名称 * @param value:信号量初始值 * @param flag:信号量标志,可取RT_IPC_FLAG_FIFO或者RT_IPC_FLAG_PRIO rt_err_t rt_sem_init (rt_sem_t sem, const char* name, rt_uint32_t value, rt_uint8_t flag); |
脱离信号量 | /** @brief 让信号量对象从内核对象管理器中移除掉 * @param sem:rt_sem_create创建处理的信号量对象 rt_err_t rt_sem_detach (rt_sem_t sem); |
获取信号量 |
/** @brief 线程通过获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号 * @param sem:信号量对象的句柄 * @param time:指定的等待时间,单位是操作系统时钟节拍 rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time); |
无等待获取信号量 | /** @brief 这个函数与rt_sem_take(sem, 0) 的作用相同 * @param sem:信号量对象的句柄 rt_err_t rt_sem_trytake(rt_sem_t sem); |
释放信号量 | /** @brief 当线程完成资源的访问后,应尽快释放它持有的信号量,使得其他线程能获得该信号量 * @param sem:信号量对象的句柄 rt_err_t rt_sem_release(rt_sem_t sem); |
2. 创建一个静态信号量
/* 信号量控制块 */
static struct rt_semaphore sem;
/* 初始化信号量,初始值是1 */
result = rt_sem_init(&sem, "sem", 1, RT_IPC_FLAG_FIFO);
3. 创建一个动态信号量
/* 指向信号量的指针 */
rt_sem_t sem = RT_NULL;
/* 创建一个信号量,初始值是1 */
sem = rt_sem_create("sem", 1, RT_IPC_FLAG_FIFO);
4. 通过信号量访问共享资源,不推荐,可能会导致优先级翻转
rt_sem_take(sem, RT_WAITING_FOREVER);/* 试图持有一个信号量,如果不成功则一直等待知道成功 */
*
访问共享资源
*
rt_sem_release(sem); /* 释放一次信号量 */
5. 使用信号量进行中断与线程同步
void USART1_IRQHandler(void)
{
接受到串口数据
rt_sem_release(sem); /* 释放信号量 */
}
void thread0(void* arg)
{
while(1)
{
rt_sem_take(sem); /* 获取信号量 */
处理串口数据
}
}
1. 互斥量相关函数
创建互斥量 | /** * @brief 完成对该互斥量控制块的初始化工作 * @param name:互斥量的名称 * @param flag:互斥量标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag); |
删除互斥量 | /** @param mutex:互斥量对象的句柄 rt_err_t rt_mutex_delete (rt_mutex_t mutex); |
初始化静态互斥量 | /** * @param mutex:互斥量对象的句柄 * @param name:互斥量的名称 * @param flag:互斥量标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag); |
脱离互斥量 | /** @brief:脱离互斥量将把互斥量对象从内核对象管理器中删除 * @param mutex:互斥量对象的句柄 rt_err_t rt_mutex_detach (rt_mutex_t mutex); |
获取互斥量 | /** @brief:线程通过互斥量申请服务获取互斥量的所有权,如果互斥量已经被当前线程线程控制,则该互斥 量的持有计数加1, * @param mutex:互斥量对象的句柄 * @param time:指定等待的时间 rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time); |
释放互斥量 | /** @brief:使用该函数接口时,只有已经拥有互斥量控制权的线程才能释放它,每释放一次该互斥量,它的持 有计数就减1,当该互斥量的持有计数为零时,它变为可用。 * @param mutex:互斥量对象的句柄 rt_err_t rt_mutex_release(rt_mutex_t mutex); |
2. 互斥量注意事项
3. 创建静态互斥量
/* 互斥量控制块*/
static rt_mutex mutex;
/* 初始化互斥量*/
rt_mutex_create(&mutex, "mutex", RT_IPC_FLAG_FIFO);
4.创建动态互斥量
/* 指向互斥量的指针 */
static rt_mutex_t mutex = RT_NULL;
/* 创建互斥锁 */
mutex = rt_mutex_create("mutex", RT_IPC_FLAG_FIFO);
5. 使用互斥量访问共享资源(例如串口),推荐使用该种方式访问共享资源,而不是信号量的方式。
void usart_send_buf(uint8_t *buf,uint32_t len)
{
rt_mutex_take(mutex, RT_WAITING_FOREVER); /* 获取互斥量 */
调用硬件串口资源输出字符
rt_mutex_release(mutex);
}
1. 事件标志组相关函数
创建事件 | /** * @brief 对事件控制块进行基本的初始化 * @param name:事件的名称 * @param flag:事件标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO rt_event_t rt_event_create (const char* name, rt_uint8_t flag); |
删除事件 | /** @param event:事件对象的句柄 rt_err_t rt_event_delete (rt_event_t event); |
初始化事件 | /** * @param event:事件对象的句柄 * @param name:事件的名称 * @param flag:事件标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag); |
脱离事件 | /** @brief:脱离事件是将事件对象从内核对象管理器中删除 * @param mutex:事件对象的句柄 rt_err_t rt_event_detach(rt_event_t event); |
接受事件 | /** @brief:内核使用32位的无符号整型数来标识事件,它的每一位代表一个事件,因此一个事件对 象可同时等 待接收32个事件。当用户调用这个接口时,首先根据set参数和接收选项来判断它要接收的事件是否 发生,如果已经发生,则根据参数option上是否设置有RT_EVENT_FLAG_CLEAR来决定是否重置 事件的相应标志位 * @param event:事件对象的句柄 * @param set:接收线程感兴趣的事件 * @param option:接收选项 * @param timeout:指定超时时间 * @param recved:指向收到的事件 rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option,rt_int32_t timeout, rt_uint32_t* recved); |
发送事件 | /** @brief:可以发送一个或多个事件 * @param event:事件对象的句柄 * @param set:接收线程感兴趣的事件 rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set); |
2. 创建静态事件
/* 事件控制块 */
static struct rt_event event;
/* 初始化事件对象 */
rt_event_init(&event, "event", RT_IPC_FLAG_FIFO);
3. 创建动态事件
/* 指向事件的地址指针 */
rt_event_t event = RT_NULL;
/* 创建事件 */
event = rt_event_create( "event", RT_IPC_FLAG_FIFO);
4. 用于中断与线程的同步
void USART1_IRQHandler(void)
{
接受到串口数据
rt_event_send(event,0x1); /*发送事件 */
}
void thread0(void* arg)
{
rt_uint32_t recved;
while(1)
{
/* 等待接收事件标志 */
rt_event_recv(test_event, /* 事件对象句柄 */
0x1, /* 接收线程感兴趣的事件 */
RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR,/* 接收选项 */
RT_WAITING_FOREVER, /* 指定超时事件, 一直等 */
&recved); /* 指向接收到的事件 */
...
处理串口数据
}
}
1. 邮箱相关函数
创建邮箱 | /** * @brief 创建动态邮箱 * @param name:邮箱的名称 * @param size:邮箱容量 * @param flag:邮箱标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag); |
删除邮箱 | /** * @param mutex:邮箱对象的句柄 rt_err_t rt_mb_delete (rt_mailbox_t mb); |
初始化邮箱 | /** * @brief 创建静态邮箱 * @param mb:邮箱对象的句柄 * @param name:邮箱的名称 * @param msgpool:缓冲区指针 * @param size:邮箱容量 * @param flag:邮箱标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool,rt_size_t size, rt_uint8_t flag) |
邮箱脱离 | /** * @brief:脱离邮箱将把邮箱对象从内核对象管理器中删除 * @param mb:邮箱对象的句柄 rt_err_t rt_mb_detach(rt_mailbox_t mb); |
发送邮件 | /** * @brief:发送的邮件可以是32位任意格式的数据,一个整型值或者一个指向缓冲区的指针 * @param mb:邮箱对象的句柄 * @param value:邮件内容 rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value); |
等待方式发送邮件 | /** * @brief:发送邮件,如果邮箱已满,则等待timeout个系统时间 * @param mb:邮箱对象的句柄 * @param value:邮件内容 * @param timeout:超时时间 rt_err_t rt_mb_send_wait (rt_mailbox_t mb, rt_uint32_t value, rt_int32_t timeout); |
接受邮件 | /** * @param mb:邮箱对象的句柄 * @param value:邮件内容 * @param timeout:超时时间 rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout); |
2. 创建静态邮箱
/* 邮箱控制块 */
static struct rt_mailbox mb;
/* 用于放邮件的内存池 */
static char mb_pool[128];
/* 初始化一个mailbox */
rt_mb_init(&mb,
"mbt", /* 名称是mbt */
&mb_pool[0], /* 邮箱用到的内存池是mb_pool */
sizeof(mb_pool)/4, /* 大小是mb_pool/4,因为每封邮件的大小是4字节 */
RT_IPC_FLAG_FIFO); /* 采用FIFO方式进行线程等待 */
3 创建动态邮箱
/* 定义邮箱控制块 */
static rt_mailbox_t mb = RT_NULL;
/* 创建一个邮箱 */
test_mail = rt_mb_create("test_mail", /* 邮箱名字 */
10, /* 邮箱大小 */
RT_IPC_FLAG_FIFO);/* 信号量模式 FIFO(0x00)*/
if (test_mail != RT_NULL)
rt_kprintf(" 邮箱创建成功!\n\n");
4. 发送与接收邮件
static char mb_str[] = "I'm a mail!";
void thread0(void* parameter)
{
while (1)
{
/* 发送mb_str1地址到邮箱中 */
rt_mb_send(&mb, (rt_uint32_t)&mb_str[0]);
}
}
void thread1(void* parameter)
{
unsigned char* str;
while (1)
{
/* 从邮箱中收取邮件 */
if (rt_mb_recv(&mb, (rt_uint32_t*)&str, RT_WAITING_FOREVER)== RT_EOK)
{
/* 处理邮箱内容 */
}
}
}
1. 消息队列相关函数
创建消息队列 | /** * @brief 创建动态消息队列 * @param name:消息队列的名称 * @param msg_size:消息队列中一条消息的最大长度 * @param max_msgs:消息队列的最大容量 * @param flag:消息队列标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO rt_mq_t rt_mq_create(const char* name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag); |
删除消息队列 | /** * @param mq:消息队列对象的句柄 rt_err_t rt_mq_delete(rt_mq_t mq); |
初始化消息队列 | /** * @brief 创建静态消息队列 * @param mq:指向静态消息队列对象的句柄 * @param name:消息队列的名称 * @param msgpool:用于存放消息的缓冲区 * @param msg_size:消息队列中一条消息的最大长度 * @param pool_size:存放消息的缓冲区大小 * @param flag:消息队列标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO 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); |
消息队列脱离 | /** * @brief:脱离消息队列将使消息队列对象被从内核对象管理器中删除 * @param mq:指向静态消息队列对象的句柄 rt_err_t rt_mq_detach(rt_mq_t mq); |
发送消息 | /** * @brief:发送的邮件可以是32位任意格式的数据,一个整型值或者一个指向缓冲区的指针 * @param mq:消息队列对象的句柄 * @param buffer:消息内容 * @param size:消息大小 rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size); |
发送紧急消息 | /** * @brief:发送邮件,如果邮箱已满,则等待timeout个系统时间 * @param mq:消息队列对象的句柄 * @param buffer:消息内容 * @param size:消息大小 rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size); |
接受消息 | /** * @param mq:消息队列对象的句柄 * @param buffer:用于接收消息的数据块 * @param size:消息大小 * @param timeout:指定的超时时间 rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer, rt_size_t size, rt_int32_t timeout); |
2. 创建静态消息队列
/* 消息队列控制块 */
static struct rt_messagequeue mq;
/* 消息队列中用到的放置消息的内存池 */
static char msg_pool[2048];
/* 初始化消息队列 */
rt_mq_init(&mq, "mqt",
&msg_pool[0], /* 内存池指向msg_pool */
128 - sizeof(void*), /* 每个消息的大小是 128 - void* */
sizeof(msg_pool), /* 内存池的大小是msg_pool的大小 */
RT_IPC_FLAG_FIFO); /* 如果有多个线程等待,按照FIFO的方法分配消息 */
3 创建动态消息队列
/* 定义消息队列控制块 */
rt_mq_t mq = RT_NULL;
/* 创建一个消息队列 */
test_mq = rt_mq_create("test_mq",/* 消息队列名字 */
40, /* 消息的最大长度 */
20, /* 消息队列的最大容量 */
RT_IPC_FLAG_FIFO);/* 队列模式 FIFO(0x00)*/
if (test_mq != RT_NULL)
rt_kprintf(" 消息队列创建成功!\n\n");
4 使用消息队列收发数据
void thread0(void* parameter)
{
char buf[] = "this is message No.x";
while (1)
{
/* 发送消息到消息队列中 */
result = rt_mq_send(&mq, &buf[0], sizeof(buf));
if ( result == -RT_EFULL)
{
/* 消息队列满 */
rt_kprintf("message queue full, delay 1s\n");
}
}
}
void thread1(void* parameter)
{
char buf[128];
while (1)
{
/* 从消息队列中接收消息 */
if (rt_mq_recv(&mq, &buf[0], sizeof(buf), RT_WAITING_FOREVER) == RT_EOK)
{
/* 处理消息 */
rt_kprintf("thread1: recv a msg, the content:%s\n", buf);
}
}
}