【04】ThreadX多线程Demo学习(二)

目录

 

简介

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明显按照以下四部分实现:

  • 预处理(引用头文件,宏定义,创建全局变量,函数声明)
  • 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风格进行应用开发。

发布了13 篇原创文章 · 获赞 0 · 访问量 266

猜你喜欢

转载自blog.csdn.net/wa0jixu/article/details/104500535