目录
简介
上篇我们介绍了ThreadX标准开发流程与工程结构,这篇我们接着分析demo_threadx.c是如何实现的。
demo_threadx.c明显按照以下四部分实现:
- 预处理(引用头文件,宏定义,创建全局变量,函数声明)
- main()中启用ThreadX kernel
- tx_application_define() 中申请系统资源
- thread_x_and_x_entry() 中实现线程回调函数
我们就按照这四部分依次分析。
1 预处理
预处理又分为以下几部分:
Step1. 调用tx_api.h
#include "tx_api.h"
Step2. 定义了线程栈,字节型内存池,块型内存池,队列缓冲区大小,便于tx_application_define() 中申请系统资源
#define DEMO_STACK_SIZE 1024
#define DEMO_BYTE_POOL_SIZE 9120
#define DEMO_BLOCK_POOL_SIZE 100
#define DEMO_QUEUE_SIZE 100
Step3. 定义了系统资源入口,由于是全局变量,因此需要考虑临界保护。
总共1个字节型内存池,1个块型内存池,1个队列,1个信号量,1个互斥锁,1个事件标志位组,8个线程(还记得上篇博客中提过的Demo资源限制么)。
/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight threads of different priorities, using a message queue, semaphore, mutex, event flags group, byte pool, and block pool. */
/* Define the ThreadX object control blocks... */
TX_THREAD thread_0;
TX_THREAD thread_1;
TX_THREAD thread_2;
TX_THREAD thread_3;
TX_THREAD thread_4;
TX_THREAD thread_5;
TX_THREAD thread_6;
TX_THREAD thread_7;
TX_QUEUE queue_0;
TX_SEMAPHORE semaphore_0;
TX_MUTEX mutex_0;
TX_EVENT_FLAGS_GROUP event_flags_0;
TX_BYTE_POOL byte_pool_0;
TX_BLOCK_POOL block_pool_0;
Step4. 定义了若干计数器,thrad_1和thread_2通过消息队列实现了消息收发,详细分析参见下文。
/* Define the counters used in the demo application... */
ULONG thread_0_counter;
ULONG thread_1_counter;
ULONG thread_1_messages_sent;
ULONG thread_2_counter;
ULONG thread_2_messages_received;
ULONG thread_3_counter;
ULONG thread_4_counter;
ULONG thread_5_counter;
ULONG thread_6_counter;
ULONG thread_7_counter;
2 入口函数
没什么可分析的,直接启动了ThreadX kernel并阻塞。
/* Define main entry point. */
int main()
{
/* Enter the ThreadX kernel. */
tx_kernel_enter();
}
3 系统资源初始化
ThreadX需要自己创建字节/块内存池,队列与线程栈开销均从指定内存池中申请,因此我们有必要掌握相关的操作方法。
3.1 一般初始化流程
tx_application_define()初始化时一般可以进行如下操作:
->创建指定大小的字节内存池:tx_byte_pool_create()
->从字节内存池中申请指定大小内存:tx_byte_allocate()
->创建指定大小的块内存池:tx_block_pool_create()
->从块内存池中申请指定大小内存:tx_block_allocate()
->创建线程,需要先申请线程栈并实现线程回调函数:tx_thread_create()
->创建队列,需要先申请队列的栈:tx_queue_create()
->创建信号量:tx_semaphore_create()
->创建事件标志位组:tx_event_flags_create()
->创建互斥锁:tx_mutex_create()
3.2 内存池操作
3.2.1 创建字节型内存池
函数定义:默认不进行各种checking。
/* Function Definition */
#ifdef TX_DISABLE_ERROR_CHECKING
UINT _tx_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start,
ULONG pool_size);
#else
#ifdef TX_ENABLE_MULTI_ERROR_CHECKING
UINT _txr_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start,
ULONG pool_size, UINT pool_control_block_size);
#else
UINT _txe_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start,
ULONG pool_size, UINT pool_control_block_size);
#endif
#endif
#define tx_byte_pool_create(p,n,s,l) _txe_byte_pool_create(p,n,s,l,(sizeof(TX_BYTE_POOL)))
实例:first_unused_memory在tx_application_define()调用时被作为参数传入。
/* Usage */
/* Create a byte memory pool from which to allocate the thread stacks. */
TX_BYTE_POOL byte_pool_0;
tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE);
3.2.2 从字节型内存池中申请内存
函数定义:这里的wait_option可以为TX_NO_WAIT,TX_WAIT_FOREVER或其它ULONG型。当没有足够内存时,wait_option为TX_NO_WAIT,则直接返回;wait_option为TX_WAIT_FOREVER,永久挂起;wait_option为其它ULONG型,则开启定时器,定时值为wait_option。定时器超时,线程恢复,并清除相关数据。
/* Function Definition */
UINT tx_byte_allocate(TX_BYTE_POOL *pool_ptr, VOID **memory_ptr, ULONG memory_size,
ULONG wait_option);
#define tx_byte_allocate _txe_byte_allocate
实例
/* Usage */
/* Allocate the stack for thread 0. */
TX_BYTE_POOL byte_pool_0;
CHAR *pointer;
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
3.2.3 释放内存到字节型内存池
函数定义
/* Function Definition */
UINT tx_byte_release(VOID *memory_ptr);
#define tx_byte_release _txe_byte_release
实例
/* Usage */
/* Release the byte back to the pool. */
tx_byte_release(pointer);
3.2.4 创建块型内存池
函数定义
/* Function Definition */
#ifdef TX_DISABLE_ERROR_CHECKING
UINT _tx_block_pool_create(TX_BLOCK_POOL *pool_ptr, CHAR *name_ptr, ULONG block_size,
VOID *pool_start, ULONG pool_size);
#else
#ifdef TX_ENABLE_MULTI_ERROR_CHECKING
UINT _txr_block_pool_create(TX_BLOCK_POOL *pool_ptr, CHAR *name_ptr, ULONG block_size,
VOID *pool_start, ULONG pool_size, UINT pool_control_block_size);
#else
UINT _txe_block_pool_create(TX_BLOCK_POOL *pool_ptr, CHAR *name_ptr, ULONG block_size,
VOID *pool_start, ULONG pool_size, UINT pool_control_block_size);
#endif
#endif
#define tx_block_pool_create(p,n,b,s,l) _txe_block_pool_create(p,n,b,s,l,(sizeof(TX_BLOCK_POOL)))
实例
/* Usage */
/* Create a block memory pool to allocate a message buffer from. */
TX_BLOCK_POOL block_pool_0;
tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
3.2.5 从块型内存池中申请内存
函数定义:wait_option参考3.2.2中描述。
/* Function Definition */
UINT tx_block_allocate(TX_BLOCK_POOL *pool_ptr, VOID **block_ptr, ULONG wait_option);
#define tx_block_allocate _txe_block_allocate
实例
/* Usage */
/* Allocate a block and release the block memory. */
TX_BLOCK_POOL block_pool_0;
CHAR *pointer;
tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
3.2.6 释放内存到块型内存池
函数定义
/* Function Definition */
UINT tx_block_release(VOID *block_ptr);
#define tx_block_release _txe_block_release
实例
/* Usage */
/* Release the block back to the pool. */
CHAR *pointer;
tx_block_release(pointer);
3.3 队列操作
3.3.1 创建队列
函数定义
/* Function Definition */
实例
/* Usage */
3.3.2 释放队列
函数定义
/* Function Definition */
实例
/* Usage */
3.3.3 入队列操作
函数定义
/* Function Definition */
实例
/* Usage */
3.3.4 出队列操作
函数定义
/* Function Definition */
实例
/* Usage */
3.4 信号量操作
3.4.1 创建信号量
函数定义
/* Function Definition */
实例
/* Usage */
3.4.2 释放信号量
函数定义
/* Function Definition */
实例
/* Usage */
3.4.3 信号量增
函数定义
/* Function Definition */
实例
/* Usage */
3.4.4 信号量减
函数定义
/* Function Definition */
实例
/* Usage */
3.5 互斥锁操作
3.5.1 创建互斥锁
函数定义
/* Function Definition */
实例
/* Usage */
3.5.2 释放互斥锁
函数定义
/* Function Definition */
实例
/* Usage */
3.5.3 上锁
函数定义
/* Function Definition */
实例
/* Usage */
3.5.4 解锁
函数定义
/* Function Definition */
实例
/* Usage */
3.6 事件标志位组操作
3.6.1 创建事件标志位组
函数定义
/* Function Definition */
实例
/* Usage */
3.6.2 释放事件标志位组
函数定义
/* Function Definition */
实例
/* Usage */
3.6.3 发送事件
函数定义
/* Function Definition */
实例
/* Usage */
3.6.4 接收事件
函数定义
/* Function Definition */
实例
/* Usage */
4 线程回调函数
4.1 线程间休眠与事件唤醒
void thread_0_entry(ULONG thread_input)
{
UINT status;
/* This thread simply sits in while-forever-sleep loop. */
while(1)
{
/* Increment the thread counter. */
thread_0_counter++;
/* Print results. */
printf("**** ThreadX Win32 Demonstration **** (c) 1996-2016 Express Logic, Inc.\n\n");
printf(" thread 0 events sent: %lu\n", thread_0_counter);
printf(" thread 1 messages sent: %lu\n", thread_1_counter);
printf(" thread 2 messages received: %lu\n", thread_2_counter);
printf(" thread 3 obtained semaphore: %lu\n", thread_3_counter);
printf(" thread 4 obtained semaphore: %lu\n", thread_4_counter);
printf(" thread 5 events received: %lu\n", thread_5_counter);
printf(" thread 6 mutex obtained: %lu\n", thread_6_counter);
printf(" thread 7 mutex obtained: %lu\n\n", thread_7_counter);
/* Sleep for 10 ticks. */
tx_thread_sleep(10);
/* Set event flag 0 to wakeup thread 5. */
status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
/* Check status. */
if (status != TX_SUCCESS)
break;
}
}
void thread_5_entry(ULONG thread_input)
{
UINT status;
ULONG actual_flags;
/* This thread simply waits for an event in a forever loop. */
while(1)
{
/* Increment the thread counter. */
thread_5_counter++;
/* Wait for event flag 0. */
status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
&actual_flags, TX_WAIT_FOREVER);
/* Check status. */
if ((status != TX_SUCCESS) || (actual_flags != 0x1))
break;
}
}
4.2 线程间操作消息队列
void thread_1_entry(ULONG thread_input)
{
UINT status;
/* This thread simply sends messages to a queue shared by thread 2. */
while(1)
{
/* Increment the thread counter. */
thread_1_counter++;
/* Send message to queue 0. */
status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
/* Check completion status. */
if (status != TX_SUCCESS)
break;
/* Increment the message sent. */
thread_1_messages_sent++;
}
}
void thread_2_entry(ULONG thread_input)
{
ULONG received_message;
UINT status;
/* This thread retrieves messages placed on the queue by thread 1. */
while(1)
{
/* Increment the thread counter. */
thread_2_counter++;
/* Retrieve a message from the queue. */
status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
/* Check completion status and make sure the message is what we
expected. */
if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
break;
/* Otherwise, all is okay. Increment the received message count. */
thread_2_messages_received++;
}
}
4.3 线程间通过信号量同步
void thread_3_and_4_entry(ULONG thread_input)
{
UINT status;
/* This function is executed from thread 3 and thread 4. As the loop
below shows, these function compete for ownership of semaphore_0. */
while(1)
{
/* Increment the thread counter. */
if (thread_input == 3)
thread_3_counter++;
else
thread_4_counter++;
/* Get the semaphore with suspension. */
status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
/* Check status. */
if (status != TX_SUCCESS)
break;
/* Sleep for 2 ticks to hold the semaphore. */
tx_thread_sleep(2);
/* Release the semaphore. */
status = tx_semaphore_put(&semaphore_0);
/* Check status. */
if (status != TX_SUCCESS)
break;
}
}
4.4 线程间通过互斥锁实现临界资源保护
void thread_6_and_7_entry(ULONG thread_input)
{
UINT status;
/* This function is executed from thread 6 and thread 7. As the loop
below shows, these function compete for ownership of mutex_0. */
while(1)
{
/* Increment the thread counter. */
if (thread_input == 6)
thread_6_counter++;
else
thread_7_counter++;
/* Get the mutex with suspension. */
status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
/* Check status. */
if (status != TX_SUCCESS)
break;
/* Get the mutex again with suspension. This shows
that an owning thread may retrieve the mutex it
owns multiple times. */
status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
/* Check status. */
if (status != TX_SUCCESS)
break;
/* Sleep for 2 ticks to hold the mutex. */
tx_thread_sleep(2);
/* Release the mutex. */
status = tx_mutex_put(&mutex_0);
/* Check status. */
if (status != TX_SUCCESS)
break;
/* Release the mutex again. This will actually
release ownership since it was obtained twice. */
status = tx_mutex_put(&mutex_0);
/* Check status. */
if (status != TX_SUCCESS)
break;
}
}
下一篇我们来分析ThreadX在跨平台方面进行了哪些设计,如何遵照ThreadX风格进行应用开发。