ThreadX(九)------消息队列Queue

本文详细介绍了ThreadX消息队列API的功能与使用方法,包括创建、删除、刷新、发送和接收消息等操作。并通过一个具体示例,展示了如何在多线程环境中利用消息队列进行数据传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

API

  • tx_queue_create
  • tx_queue_delete
  • tx_queue_flush
  • tx_queue_front_send
  • tx_queue_receive
  • tx_queue_send_notify

tx_queue_create

UINT tx_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr,
    UINT message_size,
    VOID *queue_start, ULONG queue_size);

参数

  • queue_ptr 指向消息队列控件块的指针。
  • name_ptr 指向消息队列的名称的指针。
  • message_size 指定队列中每条消息的大小。消息大小范围从 1 个 32 位单词到 16 个 32 位单词。有效消息大小选项是 1 到 16 的数值(含)。
  • queue_start 消息队列的起始地址。起始地址必须与 ULONG 数据类型的大小对齐。
  • queue_size 消息队列可用的字节总数。

返回值

  • TX_SUCCESS (0x00) 成功创建消息队列。
  • TX_QUEUE_ERROR (0x09) 无效消息队列指针。指针为 NULL 或队列已创建。
  • TX_PTR_ERROR (0x03) 消息队列的无效起始地址。
  • TX_SIZE_ERROR (0x05) 消息队列的大小无效。
  • TX_CALLER_ERROR服务(0x13)无效调用。

tx_queue_delete

UINT tx_queue_delete(TX_QUEUE *queue_ptr);

参数

  • queue_ptr 指向以前创建的消息队列的指针。

返回值

  • TX_SUCCESS (0x00) 成功删除消息队列。
  • TX_QUEUE_ERROR (0x09) 无效消息队列指针。
  • TX_CALLER_ERROR服务(0x13)无效调用。

x_queue_flush

UINT tx_queue_flush(TX_QUEUE *queue_ptr);

参数

  • queue_ptr 指向以前创建的消息队列的指针。

返回值

  • TX_SUCCESS (0x00) 成功消息队列刷新。
  • TX_QUEUE_ERROR (0x09) 无效消息队列指针。

tx_queue_front_send

UINT tx_queue_front_send(TX_QUEUE *queue_ptr,
    VOID *source_ptr, ULONG wait_option);

参数

  • queue_ptr 指向消息队列控件块的指针。
  • source_ptr 指向消息的指针。
  • wait_option 定义如果消息队列已满,服务的行为方式。等待选项的定义如下:
  1. TX_NO_WAIT (0x00000000) - TX_NO_WAIT,无论它是否成功,都会立即从该服务返回。如果从非线程调用服务,则这是唯一有效的选项;例如,初始化、计时器或 ISR。
  2. TX_WAIT_FOREVER (0xFFFF) - TX_WAIT_FOREVER,这将导致调用线程无限期挂起,直到队列中存在空间。
  3. 超时值 (0x0000001 到 0xFFFFFFFE) - 选择数值 (1-0xFFFFFFFE) 指定在等待队列中的房间时保持挂起的计时器刻度的最大数量。

返回值

  • 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上指定了除其他帐户以外的等待选项。

tx_queue_receive

UINT tx_queue_receive(TX_QUEUE *queue_ptr,
    VOID *destination_ptr, ULONG wait_option);

参数

  • queue_ptr 指向以前创建的消息队列。
  • destination_ptr 复制邮件的位置。
  • wait_option 定义如果消息队列为空,服务的行为方式。等待选项的定义如下:
  1. TX_NO_WAIT (0x00000000) - TX_NO_WAIT,无论它是否成功,都会立即从该服务返回。如果从非线程调用服务,则这是唯一有效的选项;例如,初始化、计时器或 ISR。
  2. TX_WAIT_FOREVER (0xFFFF) - TX_WAIT_FOREVER调用线程将无限期挂起,直到消息可用。
  3. 超时值 (0x0000001 到 0xFFFFFFFE) - 选择数值 (1-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的呼叫上指定的等待选项(非线程) 以外的等待选项。

tx_queue_send

UINT tx_queue_send(TX_QUEUE *queue_ptr,
    VOID *source_ptr, ULONG wait_option);

参数

  • queue_ptr 指向以前创建的消息队列。
  • source_ptr 指向消息的指针。
  • wait_option 定义如果消息队列已满,服务的行为方式。等待选项的定义如下:
  1. TX_NO_WAIT (0x00000000) - TX_NO_WAIT,无论它是否成功,都会立即从该服务返回。如果从非线程调用服务,则这是唯一有效的选项;例如,初始化、计时器或 ISR。
  2. TX_WAIT_FOREVER (0xFFFF) - TX_WAIT_FOREVER,这将导致调用线程无限期挂起,直到队列中存在空间。
  3. 超时值 (0x0000001 到 0xFFFFFFFE) - 选择数值 (1-0xFFFFFFFE) 指定在等待队列中的房间时保持挂起的计时器刻度的最大数量。

返回值

  • 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的呼叫上指定的等待选项(非线程) 以外的等待选项。

tx_queue_send_notify

UINT tx_queue_send_notify(TX_QUEUE *queue_ptr,
    VOID (*queue_send_notify)(TX_QUEUE *));

参数

  • queue_ptr 指向以前创建的队列的指针。
  • queue_send_notify 指向应用程序的队列发送通知函数的指针。如果此值为TX_NULL,则禁用通知。

返回值

  • TX_SUCCESS (0x00) 成功注册队列发送通知。
  • TX_QUEUE_ERROR (0x09) 无效队列指针。
  • TX_FEATURE_NOT_ENABLED (0xFF) 系统已编译,并禁用了通知功能。

Queue_demo

/*
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 * Queue_demo.c
 * Change Logs:
 * Date           Author       Notes
 * 2020年8月28日     	  henji      the first version
 */

/* USER CODE BEGIN Includes */
#include "tx_api.h"
#include "stdio.h"


/* USER CODE BEGIN PV */
TX_THREAD MyThread_1;
TX_THREAD MyThread_2;


/*线程栈大小*/
#define DEMO_STACK_SIZE 1024
/*内存池总大小*/
#define DEMO_BYTE_POOL_SIZE 1024*5
/*内存块池总大小*/
#define DEMO_BLOCK_POOL_SIZE 100
/*内存字节池控制块*/
TX_BYTE_POOL byte_pool_0;

/* 指向内存的指针 */
UCHAR *memory_ptr;

/* 消息队列 */
TX_QUEUE my_queue;

/* Tracex使用 */
/*跟踪缓冲区的内存大小*/
#define trace_buffer_size 64000
/*要保留在跟踪注册表中的应用程序ThreadX对象的数量*/
#define registry_entries 40
UCHAR trace_buffer_start[trace_buffer_size];
UINT trace_status;
/* USER CODE END PV */

int main(void)
{
	/* USER CODE BEGIN 2 */

	tx_kernel_enter(); //threadx 入口

	/* USER CODE END 2 */

	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while (1);
}

void MyThread_1_entry(ULONG entry_input)
{
    ULONG status;
	INT thread_1_send = 'A';
	INT special_send = 'Z';
	CHAR buf_send[19];
	while (1)
	{

		/* 紧急消息 */
		if(thread_1_send == 'C')
		{
			status = tx_queue_front_send(&my_queue,      //消息队列控制块
								         &special_send, //发送消息内容指针
									     TX_WAIT_FOREVER //无限等待
									     );
					if(status == TX_SUCCESS)
					{
						sprintf(buf_send,"special_send %c ",special_send);
						HAL_UART_Transmit(&huart1, (uint8_t*)buf_send, sizeof(buf_send), HAL_MAX_DELAY);
					}

		}
		else if(thread_1_send == 'I')
		{
			/* 到 'I' 的时候就结束进程  */
			tx_thread_terminate(&MyThread_1);
		}
		else
		{
			status = tx_queue_send(&my_queue,      //消息队列控制块
								   &thread_1_send, //发送消息内容指针
								   TX_WAIT_FOREVER //无限等待
								   );
					if(status == TX_SUCCESS)
					{
						sprintf(buf_send,"thread_1_send %c ",thread_1_send);
						HAL_UART_Transmit(&huart1, (uint8_t*)buf_send, sizeof(buf_send), HAL_MAX_DELAY);
					}
		}

		thread_1_send++;

		tx_thread_sleep(500);
	}
}

void MyThread_2_entry(ULONG entry_input)
{
	    ULONG status;
		INT thread_2_received;
		CHAR buf_rec[21];
		while (1)
		{
			status = tx_queue_receive(&my_queue, //消息队列控制块
								      &thread_2_received,//发送消息内容指针
					                  TX_WAIT_FOREVER //无限等待
					              );
			if(status == TX_SUCCESS)
			{
				sprintf(buf_rec,"thread_2_received %c ",thread_2_received);
				HAL_UART_Transmit(&huart1, (uint8_t*)buf_rec, sizeof(buf_rec), HAL_MAX_DELAY);
			}
			tx_thread_sleep(2000);

		}

}

void tx_application_define(void *first_unused_memory)
{
	/*使能追踪*/
	trace_status = tx_trace_enable(&trace_buffer_start, trace_buffer_size,registry_entries);

	/*创建一个内存池用于分配线程栈*/
	tx_byte_pool_create(&byte_pool_0, 		//内存池的指针
			"byte pool 0",//名称
			first_unused_memory,//分配内存地址
			DEMO_BYTE_POOL_SIZE//分配内存池大小
			);

	/*分配一个栈空间用于线程1*/
	tx_byte_allocate(&byte_pool_0,		   //内存池的指针
			(VOID**) &memory_ptr,		   //指向目标内存指针的指针
			DEMO_STACK_SIZE,     //分配栈大小
			TX_NO_WAIT		   //无论它是否成功,都会立即从该服务返回
			);
	/*线程1*/
	tx_thread_create(&MyThread_1,	//线程控制块指针
			"MyThread_1",//线程名字
			MyThread_1_entry,//线程入口函数
			0,//线程入口参数
			memory_ptr,//线程的起始地址
			DEMO_STACK_SIZE,//线程栈大小 K
			1,//优先级1 (0~TX_MAX_PRIORITES-1)0  表示最高优先级
			1,//禁用抢占的最高优先级
			TX_NO_TIME_SLICE,//时间切片值范围为 1 ~ 0xFFFF(TX_NO_TIME_SLICE = 0)
			TX_AUTO_START//线程自动启动
			);
	/*分配一个栈空间用于线程2*/
	tx_byte_allocate(&byte_pool_0,		   //内存池的指针
			(VOID**) &memory_ptr,		   //指向目标内存指针的指针
			DEMO_STACK_SIZE,     //分配栈大小
			TX_NO_WAIT		   //无论它是否成功,都会立即从该服务返回
			);
	/*线程2*/
	tx_thread_create(&MyThread_2,	//线程控制块指针
			"MyThread_2",//线程名字
			MyThread_2_entry,//线程入口函数
			0,//线程入口参数
			memory_ptr,//线程的起始地址
			DEMO_STACK_SIZE,//线程栈大小 K
			3,//优先级3 (0~TX_MAX_PRIORITES-1)0  表示最高优先级
			3,//禁用抢占的最高优先级
			TX_NO_TIME_SLICE,//时间切片值范围为 1 ~ 0xFFFF(TX_NO_TIME_SLICE = 0)
			TX_AUTO_START//线程自动启动
			);

	/*分配一个空间用于消息队列*/
		tx_byte_allocate(&byte_pool_0,//内存池的指针
				(VOID**) &memory_ptr, //指向目标内存指针的指针
				100,   //分配消息队列大小 100字节
				TX_NO_WAIT //无论它是否成功,都会立即从该服务返回
				);
		/* 创建消息队列 */
		tx_queue_create(&my_queue, //消息队列控制块
				"my_queue",		   //消息队列名称
				4,				   //每一个消息大小
				memory_ptr,		   //消息队列地址
				100				   //总大小100
				);


}
/* USER CODE END 4 */

thread_1 发送 ‘A’ —> ‘H’ 500 ticks
thread_1 发送 ‘C’ 的时候转变位紧急消息
thread_1 发送 ‘I’ 的时候终止进程

thread_2 接受 2000 ticks




<think>好的,用户之前询问了关于Thread-X Bootloader的内容,现在他们又想知道Thread-X系统的架构详解和目录结构。首先,我需要确认用户的需求是什么。看起来他们可能是在开发嵌入式系统,特别是使用ThreadX实时操作系统RTOS),所以需要深入了解其内部结构和文件组织,以便更好地进行开发和调试。 接下来,我需要回忆ThreadX的系统架构。ThreadX是高度模块化的,核心包括调度器、线程管理、内存管理、通信机制等。用户可能希望了解这些模块如何协同工作,以及各个目录的作用,比如源代码、配置文件、示例程序的位置。 用户之前的问题涉及引导程序,所以可能他们对系统启动流程和初始化过程特别感兴趣。在回答架构时,应该强调初始化流程,从Bootloader到内核启动的过渡。此外,他们可能需要知道如何配置ThreadX以适应不同的硬件环境,比如通过tx_initialize_low_level.s文件进行底层硬件设置。 目录结构部分,用户可能需要了解标准的ThreadX项目结构,这有助于他们组织自己的代码,找到示例和文档。需要分清楚核心模块、移植层、中间件和示例代码的位置。例如,common目录可能包含公共头文件,ports目录涉及不同处理器的移植代码,这有助于用户进行跨平台开发。 还要考虑用户可能的后续问题,比如如何添加新模块或进行调试,所以在回答中可以提到测试框架和调试工具的位置,比如test目录和trace功能。此外,安全性和扩展性也是用户可能关心的点,比如支持TEE或加密库的集成。 需要确保回答结构清晰,分点列出架构和目录,使用用户易懂的语言,避免过于技术化的术语,但也要足够详细以帮助开发者实际应用。同时,遵循用户给出的格式要求,比如数学公式用$$包裹,行内公式用$,并且使用中文回答。 最后,检查是否有遗漏的部分,比如是否提到了实时性能优化、中断处理机制,或者如何利用ThreadX的模块进行多任务管理。确保覆盖用户可能需要的所有关键点,帮助他们全面理解ThreadX的系统架构和项目结构。</think>以下是 **ThreadX 实时操作系统RTOS)的系统架构详解与目录结构解析**,按模块化分层说明: --- ### **一、ThreadX 系统架构分层** #### 1. **内核层(Core Kernel)** - **调度器** - 支持优先级抢占式调度(256 级优先级)和时间片轮转。 - 调度策略通过内部就绪队列实现,时间复杂度为 $O(1)$。 - **线程管理** - 线程控制块(TCB)存储状态(就绪、起、终止等)、栈指针和优先级。 - 动态线程创建/删除接口:`tx_thread_create()`、`tx_thread_delete()`。 - **内存管理** - 提供字节池(`TX_BYTE_POOL`)和块池(`TX_BLOCK_POOL`),支持动态内存分配。 - 零碎片算法优化,通过内存池链表实现高效管理。 - **中断处理** - 嵌套中断支持,中断服务程序(ISR)与线程上下文切换无锁设计。 - 中断延迟极低(典型值 < 100 周期)。 #### 2. **通信与同步层** - **信号量(Semaphore)** - 二进制/计数信号量,操作原子性通过关中断保证。 - **互斥量(Mutex)** - 优先级继承协议(PIP)防止优先级反转。 - **消息队列(Message Queue)** - 支持定长消息传递,通过环形缓冲区实现。 - **事件组(Event Flags)** - 32 位事件标志位,支持“与”、“或”触发条件。 #### 3. **扩展模块** - **FileX** - FAT12/16/32 文件系统驱动,集成磨损均衡算法。 - **NetX** - TCP/IP 协议栈,支持 IPv4/IPv6 和 TLS 加密。 - **USBX** - USB Host/Device 协议栈,兼容 CDC、HID、MSC 类。 #### 4. **硬件抽象层(HAL)** - **移植层(Porting Layer)** - 处理器相关代码(如上下文切换的汇编文件 `tx_thread_context_save.s`)。 - 时钟驱动(SysTick 或硬件定时器配置)。 - **低功耗模式** - 支持休眠(Sleep)和深度休眠(Deep Sleep)模式切换。 --- ### **二、ThreadX 源码目录结构详解** 典型 ThreadX 项目目录组织如下(以 ARM Cortex-M 为例): ```plaintext threadx/ ├── common/ # 核心模块源码 │ ├── inc/ # 全局头文件 (tx_api.h, tx_port.h) │ ├── src/ # 内核源码 (tx_thread_schedule.c, tx_timer.c) │ └── build/ # 编译脚本 (Makefile, IAR/Keil 工程模板) ├── ports/ # 硬件移植层 │ ├── cortex_m4/ # Cortex-M4 特定代码 │ │ ├── tx_initialize_low_level.s # 启动文件(栈初始化、中断向量表) │ │ └── tx_thread_context_save.s # 上下文切换汇编 │ └── cortex_m7/ # Cortex-M7 支持 ├── middleware/ # 扩展模块 │ ├── filex/ # FileX 文件系统 │ ├── netx/ # NetX 网络协议栈 │ └── usbx/ # USBX 驱动 ├── examples/ # 示例代码 │ ├── thread_create/ # 线程创建与同步示例 │ └── http_server/ # NetX 应用示例 ├── docs/ # 文档 │ ├── user_guide.pdf # 用户手册 │ └── porting_guide.pdf # 移植指南 └── test/ # 测试框架 ├── unit_tests/ # 单元测试(线程调度、内存分配) └── system_tests/ # 系统级压力测试 ``` --- ### **三、关键初始化流程** 系统启动代码(以 Cortex-M 为例): ```c /* 启动文件 (startup_stm32f4xx.s) */ Reset_Handler: LDR R0, =__main // 初始化 C 运行时 BLX R0 LDR R0, =tx_kernel_enter // 进入 ThreadX 内核 BX R0 /* main.c */ void tx_application_define(void *first_unused_memory) { // 定义线程、队列、内存池等对象 tx_thread_create(&thread_1, ..., entry_function, ...); } ``` --- ### **四、性能优化特性** - **确定性响应** 所有系统调用时间复杂度固定,例如信号量获取时间与系统负载无关。 - **内存占用** 最小内核配置仅需 2KB ROM 和 1KB RAM(Cortex-M0+)。 - **Trace 支持** 内置 `TX_ENABLE_EVENT_TRACE` 可实时记录线程切换、中断事件。 --- ### **五、应用场景与扩展** - **工业控制**:利用优先级抢占保障关键任务(如 PID 控制线程)。 - **物联网设备**:通过 NetX 实现 MQTT 协议与云平台通信。 - **安全领域**:集成 TrustZone 支持(如 Cortex-M33 的 TEE 环境)。 如需进一步了解某模块(如调度算法或移植细节),可指定方向深入探讨。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值