ソースを参照

【增加】初始版本。

Signed-off-by: armink <armink.ztl@gmail.com>
armink 6 年 前
コミット
dc7706de89
6 ファイル変更682 行追加0 行削除
  1. 22 0
      LICENSE
  2. 256 0
      README.md
  3. 13 0
      SConscript
  4. 253 0
      thread_pool.c
  5. 92 0
      thread_pool.h
  6. 46 0
      thread_pool_sample.c

+ 22 - 0
LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2019 Armink (armink.ztl@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 256 - 0
README.md

@@ -0,0 +1,256 @@
+# 基于 RT-Thread 的线程池实现
+
+---
+
+## 1、 基本介绍
+
+### 1.1 线程池
+
+线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
+
+- 线程池管理器(ThreadPoolManager):用于创建并管理线程池;
+- 工作线程(WorkThread):线程池中的线程;
+- 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行;
+- 任务队列(queue):用于存放没有处理的任务。提供一种缓冲机制。
+
+### 1.2 线程池的由来
+
+在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。线程池也是由此而来。
+
+## 2、 应用场景
+
+使用线程池是为了减小线程本身的开销对应用性能所产生的影响,但是其前提是线程本身创建、销毁的开销和线程执行任务的开销相比是不可忽略的。如果线程本身创建、销毁的开销对应用程序的性能可以忽略不计,那么使用/不使用线程池对程序的性能并不会有太大的影响。
+
+- 单位时间内处理的任务频繁,且任务时间较短;
+- 对实时性要求较高。如果接收到任务之后再创建线程,可能无法满足实时性的要求,此时必须使用线程池;
+- 必须经常面对高突发性事件。比如 Web 服务器。如果有足球转播,则服务器将产生巨大冲击,此时使用传统方法,则必须不停的大量创建、销毁线程。此时采用动态线程池可以避免这种情况的发生。
+
+## 3、用法
+
+主要通过以下六点介绍如何使用线程池:
+
+- 定义线程池
+- 初始化线程池
+- 添加任务到线程池
+- 销毁线程池
+- 同步锁
+- 释放同步锁
+
+### 3.1 定义线程池
+
+通过 **thread_pool** 或 **thread_pool_t** 定义线程池
+
+```c
+//方式一 结构体类型
+thread_pool pool;
+
+//方式二 结构体指针类型
+thread_pool_t pool;
+```
+*注:本文采用**方式一**定义线程池*
+
+### 3.2 初始化线程池
+
+- 原型
+
+```c
+init_thread_pool(thread_pool_t const pool, 
+               uint8_t max_thread_num, 
+               uint32_t thread_stack);
+```
+
+- API
+
+|参数|名称|类型|描述|
+|:---|:---|:---|:---|
+|入参|pool|thread_pool_t|对象|
+|入参|max_thread_num|uint8_t|线程数量|
+|入参|thread_stack|uint32_t|堆栈大小|
+|返回值|error_code|thread_pool_err|返回状态|
+
+
+- Demo
+
+创建一个线程数量为5,堆栈大小为1024 Byte的线程池
+
+```c
+thread_pool pool;
+
+init_thread_pool(pool, "A", 5, 1024);	
+```
+
+### 3.3 添加任务
+
+- 原型
+
+```c
+add_task(thread_pool_t const pool,
+        void (*process)(void *arg), 
+        void *arg);
+```
+- API 
+
+|参数|名称|类型|描述|
+|:---|:---|:---|:---|
+|入参|pool|thread_pool_t|对象|
+|入参|process(void *arg)|void|任务处理函数|
+|入参|arg|void *|任务处理函数入参|
+|返回值|error_code|thread_pool_err|返回状态|
+
+
+- Demo
+
+线程池中添加任务 task1,启动时够通过日志看到 task1 在线程池A中的运行效果。
+
+```c
+char str_a[]="A";
+//任务处理函数
+static void *task1(void *arg) {
+    LOG_D("This is %s test ",(char*)arg);
+	return NULL;
+}
+//添加任务
+pool.addTask(&pool, task1, str_a);
+
+```
+
+### 3.4 销毁线程池
+
+- 原型
+
+```c
+destroy(thread_pool_t pool);
+```
+
+- API
+
+|参数|名称|类型|描述|
+|:---|:---|:---|:---|
+|入参|pool|thread_pool_t|对象|
+|返回值|error_code|thread_pool_err|返回状态|
+
+
+- Demo
+
+销毁线程池
+
+```c
+pool.destroy(&pool);				
+```
+### 3.5 同步锁
+
+- 原型
+```c
+sync_lock(thread_pool_t pool);
+```
+- API 
+
+|入参|名称|类型|描述|
+|:---|:---|:---|:---|
+|入参|pool|thread_pool_t|对象|
+|返回值|NULL|void*|返回状态|
+
+
+- Demo
+
+```c
+pool.lock(&pool);	
+```
+
+### 3.6 释放同步锁
+
+- 原型
+
+```c
+sync_unlock(thread_pool_t pool);
+```
+
+- API 
+
+|入参|名称|类型|描述|
+|:---|:---|:---|:---|
+|入参|pool|thread_pool_t|对象|
+|返回值|NULL|void*|返回状态|
+
+
+- Demo
+
+```c
+pool.unlock(&pool);
+```
+
+## 4、示例
+
+代码位于 thread_pool_sample.c ,源码大致如下:
+
+```c
+#include <finsh.h>
+#include "thread_pool.h"
+
+static void task(void *arg) {
+    LOG_I("The task on thread %.*s is running", RT_NAME_MAX, rt_thread_self()->name);
+    rt_thread_delay(rt_tick_from_millisecond((uint32_t)arg));
+    LOG_I("The task on thread %.*s will finish", RT_NAME_MAX, rt_thread_self()->name);
+}
+
+static void thread_pool_sample(uint8_t argc, char **argv) {
+    thread_pool pool;
+
+    init_thread_pool(&pool, "sam", 3, 1024);
+    /* add 5 task to thread pool */
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    /* wait 10S */
+    rt_thread_delay(rt_tick_from_millisecond(10 * 1000));
+    /* delete all task */
+    pool.del_all(&pool);
+    /* destroy the thread pool */
+    pool.destroy(&pool);
+}
+MSH_CMD_EXPORT(thread_pool_sample, Run thread pool sample);
+```
+
+功能流程大致如下:
+
+- thread_pool_sample 中会初始化一个包含有 3 个线程的线程池
+- 向线程池中一次性添加 5 个任务
+- 每个任务执行时会延时 5S 的随机值
+- 等待 10 S 删除线程中剩余的全部任务
+- 销毁线程池
+
+使用前需在 menuconfig 中开启 `THREAD_POOL_USING_SAMPLES` 选项。
+
+开启后,在 Finsh/MSH 中执行 `thread_pool_sample` 命令,即可看到示例运行效果,大致如下:
+
+```shell
+msh />thread_pool_sample
+[D/thread_pool] create thread success.Current total thread number is 1
+[D/thread_pool] create thread success.Current total thread number is 2
+[D/thread_pool] create thread success.Current total thread number is 3
+[D/thread_pool] initialize thread pool success!
+[D/thread_pool.sample] The task on thread sam_0 is running
+[D/thread_pool] add a task to task queue success.
+[D/thread_pool.sample] The task on thread sam_1 is running
+[D/thread_pool] add a task to task queue success.
+[D/thread_pool.sample] The task on thread sam_2 is running
+[D/thread_pool] add a task to task queue success.
+[D/thread_pool] add a task to task queue success.
+[D/thread_pool] add a task to task queue success.
+[D/thread_pool.sample] The task on thread sam_1 finish
+[D/thread_pool.sample] The task on thread sam_1 is running
+[D/thread_pool.sample] The task on thread sam_1 finish
+[D/thread_pool.sample] The task on thread sam_1 is running
+[D/thread_pool.sample] The task on thread sam_0 finish
+[D/thread_pool.sample] The task on thread sam_2 finish
+[D/thread_pool.sample] The task on thread sam_1 finish
+[D/thread_pool] delete all wait task success
+[D/thread_pool] Thread pool destroy success
+```
+
+## 5、联系方式
+
+* 维护:[armink](https://github.com/armink)
+* 主页:https://github.com/armink-rtt-pkgs/thread_pool

+ 13 - 0
SConscript

@@ -0,0 +1,13 @@
+from building import *
+
+cwd  = GetCurrentDir()
+path = [cwd]
+
+src  = Glob('*.c')
+
+if GetDepend(['THREAD_POOL_USING_SAMPLES']):
+    src += Glob('thread_pool_sample.c')
+
+group = DefineGroup('thread_pool', src, depend = ['PKG_USING_THREAD_POOL'], CPPPATH = path)
+
+Return('group')

+ 253 - 0
thread_pool.c

@@ -0,0 +1,253 @@
+/*
+ * This file is part of the EasyDataManager Library.
+ *
+ * Copyright (C) 2013-2019 by Armink <armink.ztl@gmail.com>
+ *
+ * Function: a thread pool base on RT-Thread
+ * Created on: 2013-11-14
+ */
+
+#include <thread_pool.h>
+
+#define DBG_SECTION_NAME               "thread_pool"
+#define DBG_LEVEL                      DBG_LOG
+#include <rtdbg.h>
+
+#ifdef PKG_USING_THREAD_POOL
+
+static thread_pool_err add_task(thread_pool_t const pool, void (*process)(void *arg), void *arg);
+static thread_pool_err destroy(thread_pool_t pool);
+static void thread_job(void* arg);
+static void sync_lock(thread_pool_t pool);
+static void sync_unlock(thread_pool_t pool);
+static thread_pool_err del_all(thread_pool_t const pool);
+
+/**
+ * This function will initialize the thread pool.
+ *
+ * @param pool the thread_pool pointer
+ * @param name the thread_pool name
+ * @param max_thread_num the max thread number in this thread_pool
+ * @param thread_stack_size the thread stack size in this thread_pool
+ *
+ * @return error code
+ */
+thread_pool_err init_thread_pool(thread_pool_t const pool, const char* name, uint8_t max_thread_num,
+        uint32_t thread_stack_size) {
+    thread_pool_err errorCode = THREAD_POOL_NO_ERR;
+    char job_name[THREAD_POOL_NAME_MAX] = { 0 };
+    uint8_t i;
+
+    RT_ASSERT(name);
+
+    strncpy(pool->name, name, THREAD_POOL_NAME_MAX);
+    strncpy(job_name, name, THREAD_POOL_NAME_MAX);
+
+    pool->queue_lock = rt_mutex_create("tp_qlock", RT_IPC_FLAG_FIFO);
+    RT_ASSERT(pool->queue_lock != NULL);
+    pool->user_lock = rt_mutex_create("tp_ulock", RT_IPC_FLAG_FIFO);
+    RT_ASSERT(pool->user_lock != NULL);
+    pool->queue_ready = rt_sem_create("tp_qready", 0, RT_IPC_FLAG_FIFO);
+    RT_ASSERT(pool->queue_ready != NULL);
+    pool->queue_head = NULL;
+    pool->max_thread_num = max_thread_num;
+    pool->cur_wait_thread_num = 0;
+    pool->is_shutdown = RT_FALSE;
+    pool->add_task = add_task;
+    pool->del_all = del_all;
+    pool->destroy = destroy;
+    pool->lock = sync_lock;
+    pool->unlock = sync_unlock;
+    pool->thread_id = (rt_thread_t*) rt_malloc(max_thread_num * sizeof(rt_thread_t));
+    RT_ASSERT(pool->thread_id != NULL);
+    for (i = 0; i < max_thread_num; i++) {
+        rt_snprintf(job_name, THREAD_POOL_NAME_MAX, "%s_%d", name, i);
+        pool->thread_id[i] = rt_thread_create(job_name, thread_job, pool, thread_stack_size,
+                THREAD_POOL_JOB_DEFAULT_PRIORITY, THREAD_POOL_JOB_TICK * i);
+        RT_ASSERT(pool->thread_id[i] != NULL);
+        rt_thread_startup(pool->thread_id[i]);
+        LOG_D("create thread success.Current total thread number is %d", i + 1);
+        rt_thread_delay(THREAD_POOL_THREADS_INIT_TIME);
+    }
+    LOG_D("initialize thread pool success!");
+
+    return errorCode;
+}
+
+/**
+ * This function will add a task to thread pool.
+ *
+ * @param pool the thread_pool pointer
+ * @param process task function pointer
+ * @param arg task function arguments
+ *
+ * @return error code
+ */
+static thread_pool_err add_task(thread_pool_t const pool, void (*process)(void *arg), void *arg) {
+    thread_pool_err error_code = THREAD_POOL_NO_ERR;
+    thread_pool_task_t member = NULL;
+    thread_pool_task_t newtask = (thread_pool_task_t) rt_malloc(sizeof(thread_pool_task));
+    if (!newtask) {
+        LOG_W("Memory full!");
+        return THREAD_POOL_MEM_FULL_ERR;
+    }
+    newtask->process = process;
+    newtask->arg = arg;
+    newtask->next = NULL;
+    /* lock thread pool */
+    rt_mutex_take(pool->queue_lock, RT_WAITING_FOREVER);
+    member = pool->queue_head;
+    /* task queue is NULL */
+    if (member == NULL) {
+        pool->queue_head = newtask;
+    } else {
+        /* look up for queue tail */
+        while (member->next != NULL) {
+            member = member->next;
+        }
+        member->next = newtask;
+    }
+    /* add current waiting thread number */
+    pool->cur_wait_thread_num++;
+    rt_mutex_release(pool->queue_lock);
+    /* wake up a waiting thread to process task */
+    rt_sem_release(pool->queue_ready);
+    LOG_D("add a task to task queue success.");
+    return error_code;
+}
+
+/**
+ * This function will delete all wait task.
+ *
+ * @param pool the thread_pool pointer
+ *
+ * @return error code
+ */
+static thread_pool_err del_all(thread_pool_t const pool) {
+    thread_pool_err error = THREAD_POOL_NO_ERR;
+
+    rt_mutex_take(pool->queue_lock, RT_WAITING_FOREVER);
+    /* delete all task in queue */
+    for (;;) {
+        if (pool->queue_head != NULL) {
+            rt_free(pool->queue_head);
+            pool->queue_head = pool->queue_head->next;
+            pool->cur_wait_thread_num--;
+        } else {
+            break;
+        }
+    }
+    rt_sem_control(pool->queue_ready, RT_IPC_CMD_RESET, NULL);
+    LOG_D("delete all wait task success");
+    rt_mutex_release(pool->queue_lock);
+    return error;
+}
+
+/**
+ * This function will destroy thread pool.
+ *
+ * @param pool the thread_pool pointer
+ *
+ * @return error code
+ */
+static thread_pool_err destroy(thread_pool_t pool) {
+    thread_pool_err error = THREAD_POOL_NO_ERR;
+    thread_pool_task_t head = NULL;
+    uint8_t i;
+    if (pool->is_shutdown) {/* thread already shutdown */
+        error = THREAD_POOL_ALREADY_SHUTDOWN_ERR;
+    }
+    if (error == THREAD_POOL_NO_ERR) {
+        pool->is_shutdown = RT_TRUE;
+        /* wait all thread exit */
+        for (i = 0; i < pool->max_thread_num; i++) {
+            rt_thread_delete(pool->thread_id[i]);
+        }
+        /* wake up all thread from broadcast */
+        /* delete mutex and semaphore then all waiting thread will wake up */
+        rt_mutex_delete(pool->queue_lock);
+        rt_sem_delete(pool->queue_ready);
+        /* release memory */
+        rt_free(pool->thread_id);
+        pool->thread_id = NULL;
+        /* destroy task queue */
+        while (pool->queue_head != NULL) {
+            head = pool->queue_head;
+            pool->queue_head = pool->queue_head->next;
+            rt_free(head);
+        }
+        /* destroy mutex */
+        rt_mutex_delete(pool->user_lock);
+        pool = NULL;
+        LOG_D("Thread pool destroy success");
+    }
+    return error;
+}
+
+/**
+ * This function is thread job.
+ *
+ * @param arg the thread job arguments
+ *
+ */
+static void thread_job(void* arg) {
+    thread_pool_t pool = NULL;
+    thread_pool_task_t task = NULL;
+    while (1) {
+        pool = (thread_pool_t) arg;
+        /* lock thread pool */
+        rt_mutex_take(pool->queue_lock, RT_WAITING_FOREVER);
+        /* If waiting thread number is 0 ,and thread is not shutdown.
+         * The thread will block.
+         * Before thread block the queueLock will unlock.
+         * After thread wake up ,the queueLock will relock.*/
+        while (pool->cur_wait_thread_num == 0 && !pool->is_shutdown) {
+            /* ququeReady is NULL,the thread will block */
+            if (pool->queue_ready->value == 0) {
+                rt_mutex_release(pool->queue_lock);
+                rt_sem_take(pool->queue_ready, RT_WAITING_FOREVER);
+                rt_mutex_take(pool->queue_lock, RT_WAITING_FOREVER);
+            } else {/* ququeReady is not NULL,the ququeReady semaphore will decrease */
+                rt_sem_take(pool->queue_ready, RT_WAITING_FOREVER);
+            }
+        }
+        if (pool->is_shutdown) { /* thread pool will shutdown */
+            rt_mutex_release(pool->queue_lock);
+            return;
+        }
+        RT_ASSERT(pool->cur_wait_thread_num != 0);
+        RT_ASSERT(pool->queue_head != NULL);
+        /* load task to thread job */
+        pool->cur_wait_thread_num--;
+        task = pool->queue_head;
+        pool->queue_head = task->next;
+        rt_mutex_release(pool->queue_lock);
+        /* run task */
+        (*(task->process))(task->arg);
+        /* release memory */
+        rt_free(task);
+        task = NULL;
+    }
+}
+
+/**
+ * This function will lock the synchronized lock.
+ *
+ * @param pool the thread_pool pointer
+ *
+ */
+static void sync_lock(thread_pool_t pool) {
+    rt_mutex_take(pool->user_lock, RT_WAITING_FOREVER);
+}
+
+/**
+ * This function will unlock the synchronized lock.
+ *
+ * @param pool the thread_pool pointer
+ *
+ */
+static void sync_unlock(thread_pool_t pool) {
+    rt_mutex_release(pool->user_lock);
+}
+
+#endif /* PKG_USING_THREAD_POOL */

+ 92 - 0
thread_pool.h

@@ -0,0 +1,92 @@
+/*
+ * This file is part of the EasyDataManager Library.
+ *
+ * Copyright (C) 2013-2019 by Armink <armink.ztl@gmail.com>
+ *
+ * Function: a thread pool base on RT-Thread
+ * Created on: 2013-11-14
+ */
+
+#ifndef THREAD_POOL_H_
+#define THREAD_POOL_H_
+
+#include <rtthread.h>
+#include <string.h>
+
+#define THREAD_POOL_THREADS_INIT_TIME     30    /**< threads initialize average waiting time */
+#define THREAD_POOL_JOB_DEFAULT_PRIORITY  10    /**< thread poll job's priority in rt-thread */
+#define THREAD_POOL_JOB_TICK               5    /**< thread poll job's time slice in rt-thread */
+#define THREAD_POOL_NAME_MAX     RT_NAME_MAX    /**< thread poll max name length */
+
+/* thread pool error code */
+typedef enum {
+    THREAD_POOL_NO_ERR,                 /**< no error */
+    THREAD_POOL_ALREADY_SHUTDOWN_ERR,   /**< thread pool already shutdown */
+    THREAD_POOL_MEM_FULL_ERR,           /**< memory full */
+} thread_pool_err;
+
+/* a task queue which run in thread pool */
+typedef struct _thread_pool_task {
+    void (*process)(void *arg);  /**< task callback function */
+    void *arg;                   /**< task callback function's arguments */
+    struct _thread_pool_task *next;
+} thread_pool_task, *thread_pool_task_t;
+
+/* thread pool struct */
+typedef struct _thread_pool {
+    char name[THREAD_POOL_NAME_MAX + 1];/**< the name of ThreadPool, the end of name is include '\0' */
+    thread_pool_task_t queue_head;      /**< task queue which place all waiting task */
+    rt_mutex_t user_lock;               /**< a synchronized lock provided to user */
+    rt_mutex_t queue_lock;              /**< task queue mutex lock */
+    rt_sem_t queue_ready;               /**< a semaphore which for task queue ready */
+    uint8_t is_shutdown;                /**< shutdown state,if shutdown the value will equal TRUE  */
+    rt_thread_t* thread_id;             /**< thread queue which in thread pool */
+    uint8_t max_thread_num;             /**< the thread max number in thread pool */
+    uint8_t cur_wait_thread_num;        /**< the current waiting thread number in thread pool */
+    /**
+     * This function will add a task to thread pool.
+     *
+     * @param pool the ThreadPool pointer
+     * @param process task function pointer
+     * @param arg task function arguments
+     *
+     * @return error code
+     */
+    thread_pool_err (*add_task)(struct _thread_pool* const pool,
+            void (*process)(void *arg), void *arg);
+    /**
+     * This function will delete all task.
+     *
+     * @param pool
+     *
+     * @return error code
+     */
+    thread_pool_err (*del_all)(struct _thread_pool* const pool);
+    /**
+     * This function will destroy thread pool.
+     *
+     * @param pool the ThreadPool pointer
+     *
+     * @return error code
+     */
+    thread_pool_err (*destroy)(struct _thread_pool* pool);
+    /**
+     * This function will lock the synchronized lock.
+     *
+     * @param pool the ThreadPool pointer
+     *
+     */
+    void (*lock)(struct _thread_pool* pool);
+    /**
+     * This function will unlock the synchronized lock.
+     *
+     * @param pool the ThreadPool pointer
+     *
+     */
+    void (*unlock)(struct _thread_pool* pool);
+} thread_pool, *thread_pool_t;
+
+thread_pool_err init_thread_pool(thread_pool_t const pool, const char* name, uint8_t max_thread_num,
+        uint32_t thread_stack_size);
+
+#endif /* THREAD_POOL_H_ */

+ 46 - 0
thread_pool_sample.c

@@ -0,0 +1,46 @@
+/*
+ * This file is part of the EasyDataManager Library.
+ *
+ * Copyright (C) 2019 by Armink <armink.ztl@gmail.com>
+ *
+ * Function: a thread pool base on RT-Thread
+ * Created on: 2019-03-29
+ */
+
+#include <stdlib.h>
+
+#define DBG_SECTION_NAME               "thread_pool.sample"
+#define DBG_LEVEL                      DBG_LOG
+#include <rtdbg.h>
+
+#ifdef PKG_USING_THREAD_POOL
+
+#include <finsh.h>
+#include "thread_pool.h"
+
+static void task(void *arg) {
+    LOG_I("The task on thread %.*s is running", RT_NAME_MAX, rt_thread_self()->name);
+    rt_thread_delay(rt_tick_from_millisecond((uint32_t)arg));
+    LOG_I("The task on thread %.*s will finish", RT_NAME_MAX, rt_thread_self()->name);
+}
+
+static void thread_pool_sample(uint8_t argc, char **argv) {
+    thread_pool pool;
+
+    init_thread_pool(&pool, "sam", 3, 1024);
+    /* add 5 task to thread pool */
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    pool.add_task(&pool, task, (void *)(rand() % 5000));
+    /* wait 10S */
+    rt_thread_delay(rt_tick_from_millisecond(10 * 1000));
+    /* delete all task */
+    pool.del_all(&pool);
+    /* destroy the thread pool */
+    pool.destroy(&pool);
+}
+MSH_CMD_EXPORT(thread_pool_sample, Run thread pool sample);
+
+#endif /* PKG_USING_THREAD_POOL */