目录
简介
1 预处理
2 入口函数
3 系统资源初始化
3.1 一般初始化流程
3.2 内存池操作
3.2.1 创建字节型内存池
3.2.2 从字节型内存池中申请内存
3.2.3 释放内存到字节型内存池
3.2.4 创建块型内存池
3.2.5 从块型内存池中申请内存
3.2.6 释放内存到块型内存池
3.3 队列操作
3.3.1 创建队列
3.3.2 释放队列
3.3.3 入队列操作
3.3.4 出队列操作
3.4 信号量操作
3.4.1 创建信号量
3.4.2 释放信号量
3.4.3 信号量增
3.4.4 信号量减
3.5 互斥锁操作
3.5.1 创建互斥锁
3.5.2 释放互斥锁
3.5.3 上锁
3.5.4 解锁
3.6 事件标志位组操作
3.6.1 创建事件标志位组
3.6.2 释放事件标志位组
3.6.3 发送事件
3.6.4 接收事件
4 线程回调函数
4.1 线程间休眠与事件唤醒
4.2 线程间操作消息队列
4.3 线程间通过信号量同步
4.4 线程间通过互斥锁实现临界资源保护
上篇我们介绍了ThreadX标准开发流程与工程结构,这篇我们接着分析demo_threadx.c是如何实现的。
demo_threadx.c明显按照以下四部分实现:
我们就按照这四部分依次分析。
预处理又分为以下几部分:
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. 定义了若干计数器,thread_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;
没什么可分析的,直接启动了ThreadX kernel并阻塞。
/* Define main entry point. */
int main()
{
/* Enter the ThreadX kernel. */
tx_kernel_enter();
}
ThreadX需要自己创建字节/块内存池,队列与线程栈开销均从指定内存池中申请,因此我们有必要掌握相关的操作方法。
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()
函数定义:默认不进行各种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);
函数定义:这里的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);
函数定义:
/* Function Definition */
UINT tx_byte_release(VOID *memory_ptr);
#define tx_byte_release _txe_byte_release
实例:释放指定字节型内存池。
/* Usage */
/* Release the byte back to the pool. */
CHAR *pointer;
tx_byte_release(pointer);
函数定义:与字节型内存相比,块型内存在申请时还需要设置块大小block_size。
/* 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;
CHAR *pointer;
tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
函数定义: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);
函数定义:
/* 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);
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
函数定义
/* Function Definition */
实例
/* Usage */
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;
}
}
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++;
}
}
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;
}
}
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风格进行应用开发。