从零开始学ESP32:(五)ESP32/freeRTOS 实现一个线程池(池化)操作

2023-05-16

从零开始学ESP32:个人笔记记录:

芯片型号: ESP32
网络环境支持:LWIP
IDF.PY-SDK: ESP-IDF v4.3
芯片功能: freeRTOS系统

声明: 进行事件异步操作,或者非阻塞操作时候,单体循环需要处理额外的短事件时,重新考量了决定要写一个类线程池的功能,仅仅作为一个短事件处理。

// 线程池池部结构体

#define THREAD_NUMBER_MAX  128
typedef struct ST_THREAD_POOL_
{
    int         threadNumber;                           // 当前线程个数
    void*       threadReadLock;                         // 当前各个线程读锁
    void*       threadWriteLock;                        // 当前操作线程写锁
    void*       threadPollQueue;                        // 线程处理队列
   TaskHandle_t threadHandleArray[ THREAD_NUMBER_MAX ]; //不用静态数组、可以使用链表

}st_threadPool,*st_threadPool_t;

// 线程池队列式处理

typedef struct ST_THREAD_QUEUE__
{
    int  (*function)( void* );
    void* funcArgv;
}st_threadQueum,*st_threadQueum_t;

/*****************************************************************************

  • @file
  • @class
  • @brief
  • @param
  • @warning
  • @return
  • @author 线程池中主处理
  • @date 2021-11-17 14:48
    */
static void T_threadPoolFunc( st_threadPool_t tp )
{   
    int ret = 0;
    int (*fun)(void*) = NULL;
    st_threadQueum queue ={ 0 };
    while( 1 )
    {
        xSemaphoreTake( tp->threadReadLock  , portMAX_DELAY );                  // 上锁
        do{
            memset( &queue , 0, sizeof( st_threadQueum ) );
            ret = xQueueReceive( tp->threadPollQueue , &queue , portMAX_DELAY ); //进行队列等待,读取队列数据
        }while( ret == pdFALSE );
        xSemaphoreGive(tp->threadReadLock) ;                                     // 解锁
        fun = queue.function;
        if( fun ) 
        { 
            ret = (*fun)( queue.funcArgv );  // 函数指针回调
            if( ret == -1 ) { break; }       // 返回-1 就会将当前线程释放
        }                                 
    }
    vTaskDelete( NULL );
    return; 
}

/*****************************************************************************

  • @file
  • @class st_threadPool_t
  • @class st_threadQueum_t
  • @brief 创建线程池任务
  • @param NULL
  • @warning NULL
  • @return 失败返回 NULL 成功返回 thread-dev
  • @author
  • @exception 当线程池线程超过一定数量,会导致内存耗尽而奔溃,配合内存操作
    */
void* T_threadPoolCreate( int threadNum ,char* name ,int stackSize, int priority )
{   
    int i = 0;
    int ret = 0;
    char threadName[36] = { 0 };
    st_threadPool_t tp = (st_threadPool_t)malloc( sizeof( st_threadPool ) );
    if( !tp ) { goto Err_malloc; }

    memset( tp , 0 , sizeof( st_threadPool ));
/*
由于FreeRTOS的新旧版本的API不同,导致现象不同于预期,问题就在xSemaphoreCreateBinary与vSemaphoreCreateBinary的区别
用vSemaphoreCreateBinary创建的二元信号量,初始值为“满”,因为创建的同时释放了信号量
需要调用xSemaphoreGive初始化当前信号量
*/
    tp->threadReadLock = xSemaphoreCreateBinary();
    if( !tp->threadReadLock ) { goto Err_rMutex; }
    xSemaphoreGive( tp->threadReadLock );

    tp->threadWriteLock = xSemaphoreCreateBinary();
    if( !tp->threadWriteLock ) { goto Err_wMutex; }
    xSemaphoreGive( tp->threadWriteLock );

    tp->threadPollQueue = xQueueCreate( threadNum + 1, sizeof( st_threadQueum ) );
    if( !tp->threadPollQueue ) { goto Err_queue; }

    for( i = 0; i < threadNum ; i++ )
    {
        snprintf(threadName , 32 ,"tp%s_%d", name , i );
        ret = xTaskCreate( T_threadPoolFunc , threadName ,stackSize ,tp, priority, &tp->threadHandleArray[ i ] );
        if( ret != pdPASS ) { goto Err_thFork; }
    }
    tp->threadNumber = i;
    return tp;

Err_thFork  : for(int j = 0; j < i ; j++ ) { vTaskDelete( &tp->threadHandleArray[ i ] ); }
              vQueueDelete    ( tp->threadPollQueue ); 
Err_queue   : vSemaphoreDelete( tp->threadWriteLock );
Err_wMutex  : vSemaphoreDelete( tp->threadReadLock  );
Err_rMutex  : free( tp );
Err_malloc  : return NULL;
}

/*****************************************************************************

  • @file NAXC_TOOLS.c
  • @class st_threadPool_t
  • @class st_threadQueum_t
  • @brief 释放整个线程池,正在运行的任务,有系统任务管理器暂停。并不是实时释放
  • @brief 等待空闲线程进行任务线程回收
  • @param NULL
  • @warning NULL
  • @return void
  • @author HML
  • @exception
    */
void T_threadPoolDelete( st_threadPool_t tp  )
{
    if( !tp ){ return ; }
    xSemaphoreTake( tp->threadWriteLock  , portMAX_DELAY );   //上锁 
    tp->threadPollQueue = NULL;
    for(int i = 0; i < tp->threadNumber ; i++ )
    {
        vTaskDelete( tp->threadHandleArray[ i ] );
        tp->threadHandleArray[ i ] = NULL ;
    }
    vQueueDelete    ( tp->threadPollQueue );
    xSemaphoreGive  ( tp->threadWriteLock );

    vSemaphoreDelete( tp->threadWriteLock ); tp->threadWriteLock = NULL;
    vSemaphoreDelete( tp->threadReadLock  ); tp->threadReadLock  = NULL;
    free( tp );
    tp = NULL;
}

/*****************************************************************************

  • @file NAXC_TOOLS.c
  • @class st_threadPool_t
  • @class st_threadQueum_t
  • @brief 向线程池中,发送任务。
  • @brief
  • @param NULL
  • @warning NULL
  • @return void
  • @author HML
  • @exception
    */
int T_threadPoolAddTask( st_threadPool_t tp, int (*func)(void* argv ), void* argv , int timeOut_ticks )
{
    int temp = 0;
    st_threadQueum queueObj = { 0 };
    if( !tp || !tp->threadWriteLock || !tp->threadPollQueue ) { return -1; }
    xSemaphoreTake( tp->threadWriteLock  , portMAX_DELAY );   //上锁
    queueObj.function = func;
    queueObj.funcArgv = argv;
    temp = xQueueSend( tp->threadPollQueue, &queueObj , timeOut_ticks);
    xSemaphoreGive( tp->threadWriteLock ) ;                   //解锁
    return temp;
}

/**************************** 测试函数 *************************************************

  • @file NAXC_TOOLS.c
  • @class st_threadPool_t
  • @class st_threadQueum_t
  • @brief 测试函数
  • @brief
  • @param NULL
  • @warning NULL
  • @return void
  • @author HML
  • @exception
    */
int test_1(void* argc )
{
    for ( int i = 0 ; i < 100; i++ )
    {
        printf("__[%s - %d] \r\n", __FUNCTION__, __LINE__ );
    }
    return 0;
}
int test_2(void* argc )
{
    for ( int i = 0 ; i < 100; i++ )
    {
        printf("__[%s - %d] \r\n", __FUNCTION__, __LINE__ );
    }
    return 0;
}
int test_0(void* argc )
{
    for ( int i = 0 ; i < 100; i++ )
    {
        printf("__[%s - %d] \r\n", __FUNCTION__, __LINE__ );
    }
    return 0;
}

int test_threadPool_main( void * argc )
{   
    printf("__[%s - %d] \r\n", __FUNCTION__, __LINE__ );
    os_time_dly( 100 * 5 );
    printf("__[%s - %d] \r\n", __FUNCTION__, __LINE__ );
    void* tp_fd = T_threadPoolCreate( 4 , "thTest" , 1 * 1024 , 10 );
    if( tp_fd != NULL )
    {
        T_threadPoolAddTask( tp_fd , test_0 , NULL , 10 );
        T_threadPoolAddTask( tp_fd , test_1 , NULL , 10 );
        T_threadPoolAddTask( tp_fd , test_2 , NULL , 10 );
    }
    sleep ( 1000 );
    T_threadPoolDelete( tp_fd );
    return 0;
}

在当前这个版本线程池里面存在尚未解决的问题或者是其他问题,在使用时候必须要考虑到:

一、为什么在将函数加入到线程池执行前还要额外上写锁,在频繁的测试,和多线程同时调用线程池时候发现,FREERTOS的队列对线程竟态下有一定几率出现一个死机状态,提示着这一行代码(QueueGenericSend 709 )然后系统进入卡顿,直到被看门狗拉重启,所以我在发队列之前加多一把锁的原因。

二、将短处理函数放进线程池处理的时候,返回值就是队列返回值,这样处理的原因是,用户必须感知自己调用线程池时候,当前池部是否为满的。

三、里面存在一个理论逻辑BUG,就是用户无法感知当前内存池是否已经满,但是队列的空间还是空的一个反馈机制(就是全部线程都在处理完了,但是处理一个函数就有一条线程启动,但是启动之前式将队列读出来的,所以就会有这样一个问题,函数正在被处理,但是队列却空闲出来了)。 这一块在后续继续完善。

要是碰巧看到这边博文的工程师,并且有想法或者是对freeRTOS比较熟系的,希望您路过的时候不设赐教。
当前用上你的想法或者对应的方案,博文也会明确表示当您的身份和对应的贡献。
感谢。
抄袭割你JJ

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从零开始学ESP32:(五)ESP32/freeRTOS 实现一个线程池(池化)操作 的相关文章

  • 2 ROS1通讯编程基础(2)

    2 ROS1通讯编程基础 2 3 配置文件的解读2 3 1 CMakeList txt解读2 3 1 1 find package的配置2 3 1 2 messages services and actions的配置2 3 1 3 动态重配
  • Rviz 使用Arbotix控制机器人运动

    需求 控制机器人模型在 rviz 中做圆周运动 实现流程 安装 Arbotix创建新功能包 xff0c 准备机器人 urdf xacro 文件添加 Arbotix 配置文件编写 launch 文件配置 Arbotix启动 launch 文件
  • VINS问题整理

    VINS的初始化过程 xff1f 首先进行纯视觉SfM xff1a 把滑窗填满 xff0c 然后选择枢纽帧 xff08 和最后一帧有足够的视野重叠保证计算的位姿精度 xff0c 并且和最后一帧有足够的视差保证三角化地图点的精度 xff09
  • 两台ubuntu电脑如何搭建局域网以及通信

    两台ubuntu电脑如何搭建局域网以及通信 功能 xff1a 用自己的电脑代替设备中的电脑进行数据处理 xff0c 以及将最后的结果传给设备电脑 需要做的内容的 xff1a 首先用网线将自己的pc与设备连接起来 1 将自己的笔记本ip地址手
  • PC偏振控制器、锁模激光器技术、AOM声光调制器、相位噪声、锁相环、光耦合器类型

    1 PC 偏振控制器 xff08 1 xff09 什么叫做偏振光 xff1f polarized light 光是一种电磁波 xff0c 电磁波是横波 xff0c 它具有偏振性 xff0c 具有偏振性的光则称为偏振光 具体体现 xff1a
  • 小梅哥——38译码器

    三八译码器 xff0c 即是 3 种输入状态翻译成 8 种输出状态 真值表 代码展示 module decoder 3 8 a b c out input a 输入端口a input b 输入端口b input c 输入端口c output
  • 基本RS触发器(SR锁存器)

    一 前言 SR锁存器 Set Reset Latch 是静态存储单元当中最基本 xff0c 也是电路结构最简单的一种 xff0c 通常由两个或非门或者与非门组成 其中S表示Set xff0c R表示Reset 则S D称为置位端或置1输入端
  • 01-RTOS

    对于裸机而言 xff0c 对于RTOS而言 即 xff1a 对于裸机 xff0c 打游戏意味着不能回消息 回消息意味着不能打游戏 对于RTOS 打游戏和裸机的切换只需要一个时间片节拍 1ms 从宏观来看 就是同时进行的两件事 xff08 但
  • uORB笔记

    不同的类调用同一函数orb subscribe ORB ID vehicle gps position xff0c 来订阅GPS信息是 xff0c 该函数返回的值不同 xff0c 也就是说每个订阅者针对同一主题 xff0c 在调用函数orb
  • STM32 SystemInit()函数学习总结

    拿到程序后如何看系统时钟 xff1f User文件夹 system stm32f4xx程序 xff0c 先找systemcoreclock 系统时钟 xff09 但是这里这么多个系统时钟应该如何选择 点击魔法棒 xff0c 然后点击C C
  • FPGA IP核之PLL四种输出模式的理解

    一 源同步模式 使得进入管脚时的数据和上升沿的相位关系与到达芯片内部第一级寄存器时数据和上升沿的相位关系保持不变 xff08 通过调整内部的布局布线延时做到的 xff0c 用于数据接口 xff0c 特别是高速的情况下 xff09 详细理解
  • FPGA_边沿监测理解

    一 简易频率计设计中为什么一定要获取下降沿 gate a 实际闸门信号 gate a stand 将实际闸门信号打一拍之后的信号 gate a fall s 下降沿标志信号 cnt clk stand Y值 xff0c 即在实际闸门信号下
  • HAL库 STM32 串口通信

    一 实验条件 将STM32的PA9复用为串口1的TX xff0c PA10复用为串口1的RX STM32芯片的输出TX和接收RX与CH340的接收RX和发送TX相连 xff08 收发交叉且PCB上默认没有相连 xff0c 所以需要用P3跳线
  • 全局变量和局部变量

    一 C语言由四种地方可以定义变量 在函数外部定义的是全局变量 xff08 这里的函数包括main函数 xff09 在头文件中定义的是全局变量 在函数或语句块内部定义的是局部变量 函数的参数是该函数的局部变量 全局变量 xff0c 在定义位置
  • 单片机中断

    蓝桥杯单片机之中断 1 中断含义及过程 中断是指CPU在处理A事情时 xff0c 发现B请求CPU立刻去处理 xff08 中断发生 xff09 xff0c 于是CPU去处理B xff08 中断服务 xff09 xff0c 处理完B后又再次回
  • AprilTag的使用、相关问题及解决方法

    使用棋盘格标定相机 安装标定功能包 span class token function sudo span span class token function apt get span span class token function i
  • 对接海康综合安防管理平台经验总结

    前言 xff1a 因业务需要对接海康威视的综合安防管理平台获得下属所管理的摄像头 xff0c 根据摄像头code获得监控视频流信息 1 详情可以浏览海康开放平台 xff0c 在官网上有对应的接入指南以及开放的API接口 前提是本地已部署了海
  • 【环境配置】Visual Studio opencv配置

    需求 在Visual Studio环境中编写C 43 43 代码 xff0c 同时可以调用OpenCV的相关代码 1 安装OpenCV 访问 opencv 官网下载对应平台的库文件 注意 xff1a Visual Studio和OpenCV
  • MySQL常见用法

    文章目录 一 时间类1 1 DATE SUB 函数1 2 NOW CURDATE CURTIME DATE 函数1 3 实战 二 统计类三 字符类3 1 LOCATE 函数3 2 concat 函数3 3 concat ws 函数3 4 g
  • 牢记公式,ardupilot EKF2就是纸老虎(四)!

    版权声明 xff1a 本文为博主原创文章 xff0c 转载请附上博文链接 xff01 四 一睹EKF2芳容 因为篇幅过长 xff0c 写的一些公式会乱码 xff0c 没办法只能把 牢记公式 xff0c ardupilot EKF2就是纸老虎

随机推荐