函数指针数组、钩子函数、回调函数 应用

说明:本文主要记录和讲解 函数指针函数指针数组回调函数,钩子函数的应用。   

1.函数指针

    函数指针是指向函数的指针变量。通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。函数指针可以像一般函数一样,用于调用函数、传递参数。C在编译时,每一个函数都有一个入口地址,这个入口地址就是函数指针所指向的地址,有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是相似的。
函数指针有两个用途:调用函数和做函数的参数,做函数参数就是回调函数和钩子函数的用途。

函数指针变量的声明:

typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型

2.回调函数、钩子函数

        回调函数也叫钩子函数,是将函数指针作为某个函数的参数传入函数,并在函数内部再调用传入的函数指针(回调函数也叫钩子函数)。
简单讲:回调函数是由别人的函数执行时调用你的函数。

   

3.函数指针、回调函数、钩子函数的应用范例

以下代码是取自 RT-Thread 3.1.5 的 idle.c 空闲线程文件,文件中应用了钩子函数,函数指针,函数指针数组,通过学习源码及注释可以参考和借鉴以上功能的应用。

文件路径:... \Local\Arm\Packs\RealThread\RT-Thread\3.1.5\src\idle.c

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2006-03-23     Bernard      the first version
 * 2010-11-10     Bernard      add cleanup callback function in thread exit.
 * 2012-12-29     Bernard      fix compiling warning.
 * 2013-12-21     Grissiom     let rt_thread_idle_excute loop until there is no
 *                             dead thread.
 * 2016-08-09     ArdaFu       add method to get the handler of the idle thread.
 * 2018-02-07     Bernard      lock scheduler to protect tid->cleanup.
 * 2018-07-14     armink       add idle hook list
 * 2018-11-22     Jesven       add per cpu idle task
 *                             combine the code of primary and secondary cpu
 */

#include <rthw.h>
#include <rtthread.h>

#define RT_USING_HEAP
#define RT_USING_HOOK          /* 钩子函数功能开关 */

#if defined (RT_USING_HOOK)
#ifndef RT_USING_IDLE_HOOK     
#define RT_USING_IDLE_HOOK
#endif
#endif

#ifndef IDLE_THREAD_STACK_SIZE
#if defined (RT_USING_IDLE_HOOK) || defined(RT_USING_HEAP)
#define IDLE_THREAD_STACK_SIZE  256
#else
#define IDLE_THREAD_STACK_SIZE  128    /* 空闲线程栈大小 */
#endif
#endif

extern rt_list_t rt_thread_defunct;

static struct rt_thread idle;         /* 空闲线程句柄 */
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_thread_stack[IDLE_THREAD_STACK_SIZE];

#ifdef RT_USING_IDLE_HOOK
#ifndef RT_IDLE_HOOK_LIST_SIZE
#define RT_IDLE_HOOK_LIST_SIZE  4
#endif

static void (*idle_hook_list[RT_IDLE_HOOK_LIST_SIZE])(void);   /* 定义空闲线程钩子函数列表:函数指针数组定义 */

/**
 * @ingroup Hook  
 * This function sets a hook function to idle thread loop. When the system performs
 * idle loop, this hook function should be invoked.
 * 添加空闲线程的钩子函数,传入一个函数指针,此函数将入参增加到空闲线程的钩子函数队列中。
 * @param hook the specified hook function 需要增加的钩子函数,函数指针
 *
 * @return RT_EOK: set OK      设置为OK
 *         -RT_EFULL: hook list is full 钩子函数队列已满
 *
 * @note the hook function must be simple and never be blocked or suspend.  
 *  钩子函数必须简单,并且永远不要被阻塞或挂起
 */
rt_err_t rt_thread_idle_sethook(void (*hook)(void))
{
    rt_size_t i;
    rt_base_t level;
    rt_err_t ret = -RT_EFULL;

    /* disable interrupt 关闭中断 */
    level = rt_hw_interrupt_disable();

    for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
    {
        if (idle_hook_list[i] == RT_NULL)  /* 查找函数指针数组中的空位置,查找到空位置时把钩子函数放进去 */
        {
            idle_hook_list[i] = hook;
            ret = RT_EOK;
            break;
        }
    }
    /* enable interrupt 开启中断 */
    rt_hw_interrupt_enable(level);

    return ret;
}

/**
* delete the idle hook on hook list  删除空闲线程钩子函数队列中的某个成员
 *
 * @param hook the specified hook function 需要删除的钩子函数
 *
 * @return RT_EOK: delete OK  删除成功
 *         -RT_ENOSYS: hook was not found  没有找到入参对应钩子函数
 */
rt_err_t rt_thread_idle_delhook(void (*hook)(void))
{
    rt_size_t i;
    rt_base_t level;
    rt_err_t ret = -RT_ENOSYS;

    /* disable interrupt 关闭中断 */
    level = rt_hw_interrupt_disable();

    for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++) 
    {
        if (idle_hook_list[i] == hook)  /* 查找钩子函数队列中成员符合入参钩子的位置,查找到后把对应位置置空 */
        {
            idle_hook_list[i] = RT_NULL;
            ret = RT_EOK;
            break;
        }
    }
    /* enable interrupt 开启中断 */
    rt_hw_interrupt_enable(level);

    return ret;
}

#endif

#ifdef RT_USING_HEAP
/* Return whether there is defunctional thread to be deleted. 返回是否存在要删除的失效线程 */
rt_inline int _has_defunct_thread(void)
{
    /* The rt_list_isempty has prototype of "int rt_list_isempty(const rt_list_t *l)".
     * So the compiler has a good reason that the rt_thread_defunct list does
     * not change within rt_thread_idle_excute thus optimize the "while" loop
     * into a "if".
     *
     * So add the volatile qualifier here. */
    const volatile rt_list_t *l = (const volatile rt_list_t *)&rt_thread_defunct;

    return l->next != l;
}
#endif

/**
 * @ingroup Thread
 *
 * This function will perform system background job when system idle.
 * 当系统空闲时,此功能将执行系统后台作业
 */
void rt_thread_idle_excute(void)
{
    /* Loop until there is no dead thread. So one call to rt_thread_idle_excute
     * will do all the cleanups. */
    /* disable interrupt */

    RT_DEBUG_NOT_IN_INTERRUPT;

#ifdef RT_USING_HEAP
    while (1)
    {
        rt_base_t lock;
        rt_thread_t thread;

        /* disable interrupt 关闭中断 */
        lock = rt_hw_interrupt_disable();

        /* check whether list is empty */
        if (!_has_defunct_thread())
        {
            rt_hw_interrupt_enable(lock);
            break;
        }
        /* get defunct thread */
        thread = rt_list_entry(rt_thread_defunct.next,
                struct rt_thread,
                tlist);
        /* remove defunct thread */
        rt_list_remove(&(thread->tlist));
        /* release thread's stack */
        RT_KERNEL_FREE(thread->stack_addr);
        /* delete thread object */
        rt_object_delete((rt_object_t)thread);
        rt_hw_interrupt_enable(lock);
    }
#endif
}

extern void rt_system_power_manager(void);
static void rt_thread_idle_entry(void *parameter) /* 空闲线程 */
{
    while (1)
    {

#ifdef RT_USING_IDLE_HOOK
        rt_size_t i;

        for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)  /* 查找并运行空闲线程钩子函数队列中的钩子函数 */
        {
            if (idle_hook_list[i] != RT_NULL)
            {
                idle_hook_list[i](); /* 运行钩子函数 ,函数指针调用*/
            }
        }
#endif

        rt_thread_idle_excute();
#ifdef RT_USING_PM
        rt_system_power_manager();
#endif
                   RT_THREAD_PRIORITY_MAX - 1,
    }
}

/**
 * @ingroup SystemInit
 *
 * This function will initialize idle thread, then start it.
 *
 * @note this function must be invoked when system init.
 */
void rt_thread_idle_init(void)
{
    /* initialize thread 创建一个静态线程 */
    rt_thread_init(&idle,                    /* 线程句柄 */
                   "tidle",                  /* 线程的名称 */
                   rt_thread_idle_entry,     /* 线程入口函数 */
                   RT_NULL,                  /* 线程入口函数参数 */
                   &rt_thread_stack[0],      /* 线程栈起始地址 */
                   sizeof(rt_thread_stack),  /* 线程栈大小,单位是字节 */
                   32);                      /* 线程的优先级 */ 

    /* startup */
    rt_thread_startup(&idle);                /* 启动线程 */  
}

/**
 * @ingroup Thread
 *
 * This function will get the handler of the idle thread.
 *
 */
rt_thread_t rt_thread_idle_gethandler(void)
{
    return (rt_thread_t)(&idle);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值