文章参考:
ThreadX学习(9)——消息队列_threadx消息队列-CSDN博客
消息队列是ThreadX中线程间(以及线程和中断间)通信的主要手段。
为什么需要消息队列,而不直接使用全局数组?
在裸机编程时,使用全局数组的确比较方便,但是在加上 RTOS 后就是另一种情况了。
相比消息队列,使用全局数组主要有如下四个问题:
- 使用消息队列可以有效管理线程,而全局数组无法做到,线程的超时机制需要用户自己去实现。
- 使用全局数组要防止多线程的访问冲突,而使用消息队列则处理好了这个问题,用户无需担心。
- 使用消息队列可以有效地解决中断服务程序与线程之间消息传递的问题。
- FIFO 机制更有利于数据的处理。
1.tx_queue_create
TX_QUEUE queue_ptr;//先定义再创建
UINT tx_queue_create( TX_QUEUE *queue_ptr,
CHAR *name_ptr,
UINT message_size,
VOID *queue_start,
ULONG queue_size)
创建消息队列:
第 1 个参数 queue_ptr 是消息队列控制块指针。
第 2 个参数 name_ptr 是消息队列名称字符串。
第 3 个参数 message_size 是每个消息的大小。
第 4 个参数 queue_start 是消息队列缓冲区的起始地址。起始地址必须与ULONG数据类型的大小对齐。
第 5 个参数 queue_size 是消息队列的总大小。
返回值:
TX_SUCCESS:(0x00)成功创建消息队列。
TX_QUEUE_ERROR:(0x09)无效的消息队列指针。要么指针是NULL,要么队列已经创建。
TX_PTR_ERROR: (0x03)无效的消息队列起始地址。
TX_SIZE_ERROR: (0x05)消息队列大小无效。
TX_CALLER_ERROR:(0x13)无效的服务调用者。
消息队列创建函数需要在tx_application_define里定义。根据串口打印结果可以看到,已经成功创建消息队列。
VOID tx_application_define(void *first_unused_memory)
{
char buffer[256];
UINT dd=tx_queue_create(&queue_ptr,"queue 0",16,first_unused_memory,128);
huartsend(dd);
UINT aa= tx_semaphore_create(&semaphore_ptr,"semaphore 0",1);
snprintf(buffer,sizeof(buffer),"%u\n",aa);
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
UINT bb = tx_event_flags_create(&group_ptr,"group 0");
huartsend(bb);
UINT cc= tx_event_flags_set_notify(&group_ptr, event_flags_notify_callback);
//调用事件标志组设置通知函数
huartsend(cc);
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
thread_0_stack, DEMO_STACK_SIZE,
1, 1, 10, TX_AUTO_START);
tx_thread_create(&thread_1, "Thread 1", thread_1_entry, 0,
thread_1_stack, DEMO_STACK_SIZE,
2, 2, TX_NO_TIME_SLICE, TX_AUTO_START);
}
2.tx_queue_send
UINT tx_queue_send(TX_QUEUE *queue_ptr,
VOID *source_ptr,
ULONG wait_option)
发送消息:
第 1 个参数 queue_ptr 是消息队列控制块指针。
第 2 个参数 source_ptr 是需发送消息的指针。
第 3 个参数 wait_option 是等待选项:
TX_NO_WAIT (0x00000000),表示不管消息队列是否满,立即返回。如果在定时器组,初始
化或中断里面调用,必须要设置成这个参数。
TX_WAIT_FOREVER (0xFFFFFFFF),表示永久等待,直到消息队列有空间可用。
等待时间,范围 0x00000001 到 0xFFFFFFFE,单位为系统时钟节拍。
返回值:
TX_SUCCESS: (0x00)消息发送成功。
TX_DELETED: (0x01)线程挂起时消息队列被删除。
TX_QUEUE_FULL: (0x0B)在指定的等待时间内队列已满。
TX_WAIT_ABORTED: (0x1A)挂起被另一个线程、计时器或中断中止。
TX_QUEUE_ERROR:(0x09)无效的消息队列指针。
TX_PTR_ERROR:(0x03)消息的源指针无效。
TX_WAIT_ERROR: (0x04)在非线程调用时指定了TX_NO_WAIT以外的等待选项。
在线程0中线发送消息,再打印消息。
void thread_0_entry(ULONG thread_input)
//线程,串口发送数据
{
CHAR *name;
ULONG enqueued;
ULONG available_storage;
TX_THREAD *first_suspended;
ULONG suspended_count;
TX_QUEUE *next_queue;
char message[] = "hello threadx!";
UINT aa=tx_queue_send(&queue_ptr,&message,TX_NO_WAIT);
huartsend(aa);
UINT bb=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
char buffer[256];
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
}
3. tx_queue_receive
UINT tx_queue_receive(TX_QUEUE *queue_ptr,
VOID *destination_ptr,
ULONG wait_option);
接收消息:
第 1 个参数 queue_ptr 是消息队列的指针。
第 2 个参数 destination_ptr 是接收消息存储的位置。
第 3 个参数 wait_option 是等待选项:
TX_NO_WAIT:(0 x00000000)
TX_WAIT_FOREVER: (0xFFFFFFFF)
等待时间:(0x00000001 ~ 0xFFFFFFFE)
返回值
TX_SUCCESS: (0x00)成功接收消息。
TX_DELETED: (0x01)线程挂起时消息队列被删除。
TX_QUEUE_EMPTY: (0x0A)等待时间内队列为空。
TX_WAIT_ABORTED: (0x1A)挂起被另一个线程、计时器或ISR中止。
TX_QUEUE_ERROR:(0x09)无效的消息队列指针。
TX_PTR_ERROR:(0x03)无效的接收消息存储指针。
TX_WAIT_ERROR: (0x04)在非线程调用时指定了TX_NO_WAIT以外的等待选项。
在之前的示例代码后面写消息队列接收函数,然后打印消息队列信息。
void thread_0_entry(ULONG thread_input)
//线程,串口发送数据
{
CHAR *name;
ULONG enqueued;
ULONG available_storage;
TX_THREAD *first_suspended;
ULONG suspended_count;
TX_QUEUE *next_queue;
char message[] = "hello threadx!";
UINT aa=tx_queue_send(&queue_ptr,&message,TX_NO_WAIT);
huartsend(aa);
UINT bb=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(bb);
char buffer[256];
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
ULONG destination_ptr;
UINT cc=tx_queue_receive(&queue_ptr,
&destination_ptr,
TX_WAIT_FOREVER);
huartsend(cc);
UINT dd=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(dd);
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
}
4.tx_queue_info_get
UINT tx_queue_info_get( TX_QUEUE *queue_ptr,
CHAR **name,
ULONG *enqueued,
ULONG *available_storage
TX_THREAD **first_suspended,
ULONG *suspended_count,
TX_QUEUE **next_queue);
获取消息队列信息:
第 1 个参数 queue_ptr 是消息队列控制块指针。
第 2 个参数 name 是消息队列名字符串,获取后存储的指针。
第 3 个参数 enqueued 是消息队列中现有消息数量,所存储的指针。
第 4 个参数 available_storage 是消息队列中剩余空间,所存储的指针。
第 5 个参数 first_suspended 是消息队列挂起列表的第一个线程,所存储的指针。
第 6 个参数 suspended_count 是消息队列挂起列表的线程数,所存储的指针。
第 7 个参数 next_queue 是下一个消息队列,所存储的指针。
返回值:
TX_SUCCESS: (0x00)成功获取队列信息。
TX_QUEUE_ERROR:(0x09)无效的消息队列指针。
参数输入TX_NULL(0x00)表示不需要该参数。
相关示例代码在发送消息和接收消息函数中已经涉及。
5.tx_queue_delete
UINT tx_queue_delete(TX_QUEUE *queue_ptr);
删除消息队列:
第 1 个参数 queue_ptr 是消息队列控制块指针。
返回值:
TX_SUCCESS: (0x00)成功删除消息队列。
TX_QUEUE_ERROR:(0x09)无效的消息队列指针。
TX_CALLER_ERROR:(0x13)无效的服务调用者。
所有挂起等待此队列的线程都将恢复,并给出TX_DELETED返回状态。
在线程0中删除消息,可以看到删除成功。
void thread_0_entry(ULONG thread_input)
//线程,串口发送数据
{
CHAR *name;
ULONG enqueued;
ULONG available_storage;
TX_THREAD *first_suspended;
ULONG suspended_count;
TX_QUEUE *next_queue;
char message[] = "hello threadx!";
UINT aa=tx_queue_send(&queue_ptr,&message,TX_NO_WAIT);
huartsend(aa);
UINT bb=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(bb);
char buffer[256];
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
CHAR buffer1[32];
UINT cc=tx_queue_receive(&queue_ptr,
buffer1,
TX_WAIT_FOREVER);
huartsend(cc);
HAL_UART_Transmit(&huart1,(uint8_t *)buffer1,strlen(buffer1),HAL_MAX_DELAY);
UINT dd=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(dd);
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
UINT ee= tx_queue_delete(&queue_ptr);
huartsend(ee);
}
6.tx_queue_flush
UINT tx_queue_flush(TX_QUEUE *queue_ptr);
清空消息队列:
第 1 个参数 queue_ptr 是消息队列控制块指针。
返回值:
TX_SUCCESS: (0x00)成功刷新消息队列。
TX_QUEUE_ERROR:(0x09)无效的消息队列指针。
如果队列已满,则丢弃所有挂起线程的消息,然后恢复每个挂起的线程,返回状态表明消息发送成功。如果队列为空,则此服务不执行任何操作。
示例代码先清空消息队列,再打印消息队列信息。
void thread_0_entry(ULONG thread_input)
//线程,串口发送数据
{
CHAR *name;
ULONG enqueued;
ULONG available_storage;
TX_THREAD *first_suspended;
ULONG suspended_count;
TX_QUEUE *next_queue;
char message[] = "hello threadx!";
UINT aa=tx_queue_send(&queue_ptr,&message,TX_NO_WAIT);
//发送
huartsend(aa);
UINT bb=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(bb);
char buffer[256];
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
UINT cc= tx_queue_flush(&queue_ptr);
huartsend(cc);
UINT dd=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(dd);
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
}
7.tx_queue_front_send
UINT tx_queue_front_send(TX_QUEUE *queue_ptr,
VOID *source_ptr,
ULONG wait_option);
发送紧急消息插队到队首:
第 1 个参数 queue_ptr 是消息队列控制块指针。
第 2 个参数 source_ptr 是需发送消息的指针。
第 3 个参数 wait_option 是等待选项。
返回值:
TX_SUCCESS: (0x00)消息发送成功。
TX_DELETED: (0x01)线程挂起时消息队列被删除。
TX_QUEUE_FULL: (0x0B)服务无法发送消息,因为在指定的等待时间内队列已满。
TX_WAIT_ABORTED: (0x1A)挂起被另一个线程、计时器或ISR中止。
TX_QUEUE_ERROR:(0x09)无效的消息队列指针。
TX_PTR_ERROR:(0x03)消息的源指针无效。
TX_WAIT_ERROR: (0x04)在非线程调用时指定了TX_NO_WAIT以外的等待选项。
先发送一个消息,再发送一个插队消息,可以看到,接收到的是插队消息,因此,发送紧急消息插队到队首函数调用成功。
void thread_0_entry(ULONG thread_input)
//线程,串口发送数据
{
CHAR *name;
ULONG enqueued;
ULONG available_storage;
TX_THREAD *first_suspended;
ULONG suspended_count;
TX_QUEUE *next_queue;
char message1[] = "hello threadx!1";
UINT aa=tx_queue_send(&queue_ptr,&message1,TX_NO_WAIT);
char message3[] = "dddddd\n";
//UINT ac=tx_queue_send(&queue_ptr,&message3,TX_NO_WAIT);
UINT fontmsg=tx_queue_front_send(&queue_ptr,&message3,TX_NO_WAIT);
//发送
huartsend(aa);
UINT bb=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(bb);
char buffer[256];
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
char buffer1[32];
tx_queue_receive(&queue_ptr,&buffer1,TX_NO_WAIT);
HAL_UART_Transmit(&huart1,(uint8_t *)buffer1,strlen(buffer1),HAL_MAX_DELAY);
UINT dd=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(dd);
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
}
8.tx_queue_prioritize
UINT tx_queue_prioritize(TX_QUEUE *queue_ptr);
挂起列表中最高优先级线程提到队首:
第 1 个参数 queue_ptr 是消息队列控制块指针。
返回值:
TX_SUCCESS:(0x00)成功。
TX_QUEUE_ERROR:(0x09)无效的消息队列指针。
在上述示例代码后面写一个挂起列表中最高优先级线程提到队首函数,并打印函数返回值,可以看到,函数返回值是0。
void thread_0_entry(ULONG thread_input)
//线程,串口发送数据
{
CHAR *name;
ULONG enqueued;
ULONG available_storage;
TX_THREAD *first_suspended;
ULONG suspended_count;
TX_QUEUE *next_queue;
char message1[] = "hello threadx!1";
UINT aa=tx_queue_send(&queue_ptr,&message1,TX_NO_WAIT);
char message3[] = "dddddd\n";
//UINT ac=tx_queue_send(&queue_ptr,&message3,TX_NO_WAIT);
UINT fontmsg=tx_queue_front_send(&queue_ptr,&message3,TX_NO_WAIT);
//发送
huartsend(aa);
UINT bb=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(bb);
char buffer[256];
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
char buffer1[32];
tx_queue_receive(&queue_ptr,&buffer1,TX_NO_WAIT);
HAL_UART_Transmit(&huart1,(uint8_t *)buffer1,strlen(buffer1),HAL_MAX_DELAY);
UINT dd=tx_queue_info_get(&queue_ptr,
&name,
&enqueued,
&available_storage,
&first_suspended,
&suspended_count,
&next_queue);
huartsend(dd);
snprintf(buffer,sizeof(buffer),"queue name:%s\nenqueued:%lu\navailable_storage:%lu\nsuspended_count:%lu\n",name,enqueued,available_storage,suspended_count);\
HAL_UART_Transmit(&huart1,(uint8_t *)buffer,strlen(buffer),HAL_MAX_DELAY);
UINT gg= tx_queue_prioritize(&queue_ptr);
huartsend(gg);
}
9.tx_queue_send_notify
UINT tx_queue_send_notify( TX_QUEUE *queue_ptr,
VOID (*queue_send_notify)(TX_QUEUE *));
发送通知回调:
第 1 个参数 queue_ptr 是消息队列控制块指针。
第 2 个参数 queue_send_notify 是队列发送通知函数的指针。如果该值为TX_NULL,则禁用通知。
返回值:
TX_SUCCESS: (0x00)队列发送通知注册成功。
TX_QUEUE_ERROR:(0x09)无效的队列指针。
TX_FEATURE_NOT_ENABLED: (0xFF)系统编译时禁用了通知功能。
当消息被发送到指定队列时将调用queue_send_notify函数(自定义)。发送通知回调不允许调用任何带有挂起选项的 API。
在tx_application_define写发送通知回调函数,并定义该函数。
void queue_send_notify_function(TX_QUEUE *queue_ptr);
VOID tx_application_define(void *first_unused_memory)
{
UINT dd=tx_queue_create(&queue_ptr,"queue 0",16,first_unused_memory,128);
huartsend(dd);
UINT ee= tx_queue_send_notify(&queue_ptr, queue_send_notify_function);
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
thread_0_stack, DEMO_STACK_SIZE,
1, 1, 10, TX_AUTO_START);
tx_thread_create(&thread_1, "Thread 1", thread_1_entry, 0,
thread_1_stack, DEMO_STACK_SIZE,
2, 2, TX_NO_TIME_SLICE, TX_AUTO_START);
}
void queue_send_notify_function(TX_QUEUE *queue_ptr)
{
UINT aa=888888;
huartsend(aa);
}