一、回调函数
1、定义:
网上比较官方的定义为,把函数的指针(地址)作为参数传递给另一个函数。
当这个函数指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
2、功能:
自动返回给使用者的函数。
如果是硬件出身的同事,可以把回调函数理解成中断。
3、个人理解:
笔者个人是这么理解的,这东西就有点像叫在宿舍叫外卖。
没使用回调函数之前,我只能去门店里面下单,然后等着出餐,在出餐的这段时间你只能在门店等着,不能回宿舍游戏。
使用回调函数之后,我直接在外卖平台下单,还可以在宿舍再开一把游戏,等到外卖到了从游戏状态马上切换成干饭状态。
所以在使用回调函数之后,我有更多的时间去做自己想做的事情,在时间管理大师方面修为更进一步。
4、意义:
笔者在实际使用回调函数过程中,最大的感触就是回调函数可以提高程序功能的运行效率以及性能。
在实时性高的场景,假设有一个模块一直主动通过串口232给PC端发消息。
没使用回调函数之前,使用传统轮询的方法,在接收模块的消息可能没法那么及时。
但是在使用回调函数后,在接收模块的消息时就可以马上接收马上反馈。
二、回调函数的步骤:
1、模块书写回调函数注册接口:
2、模块内部实现回调函数的调用;
3、主函数将回调函数注册给模块;
4、模块内部等到合适的契机,调用主函数。
三、示例:
这里举一个例子,现在有一个模块moudule,我们想让模块moudule主动给main一直发消息。
而不需要main每次调用到模块moudule的函数,模块moudule才会给main发一次消息。
1、模块moudule头文件声明
/***************moudule_api.h*************************************/
#include "moudule_api.h"
//模块回调给main的消息枚举
emum emSessionType
{
emSessionType_SayHallo = 0,
emSessionType_InquireName = 1,
emSessionType_SayBye = 2
}
//声明回调函数的函数指针
typedef void (*CallFun)(int p_iType, char *p_cData, void *userParam);
//模块开始执行
void vMouduleAPI_StartRun();
//回调函数注册
void vMouduleAPI_RegisterCallFun(CallFun p_pvCallFun);
2、模块moudule功能源码实现
/****************moudule.c**************************************/
#include "moudule_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static CallFun m_pCallBack=NULL;//记录main中传过来的函数指针
static emSessionType m_iSessionType;//发给main的消息类型
//注册main中传过来的回调函数
void vCommom_CallBackEventFun(CallFun p_pvCallFun)
{
m_pCallBack = p_pvCallFun;
m_iSessionType = 0;
}
void vMouduleAPI_start_run()
{
char l_cPrintData[48] = {0};
memset(l_cPrintData, 0x00, sizeof(l_cPrintData));
while(1)
{
//函数内部适当加sleep,避免过度占用系统资源,让系统可以正常调度CPU
usleep(1000);
if(NULL == m_pCallBack)
{
continue;
}//if(NULL == pCallBack)
//发送给main的数据,在发送前最好初始化,否则可能会有乱码
memset(l_cPrintData, 0x00, sizeof(l_cPrintData));
switch(m_iSessionType)
{
case emSessionType_SayHallo:
strncpy(l_cPrintData, "Moudule_Say=>Hello\n");
//调用main传过来的函数指针,主动发Hello消息给main
m_pCallBack(emSessionType_SayHallo, l_cPrintData, NULL);
break;
case emSessionType_InquireName:
strncpy(l_cPrintData, "Moudule_Inquire=>What't your name\n");
//调用main传过来的函数指针,主动发“What't your name”消息给main
m_pCallBack(emSessionType_InquireName, l_cPrintData, NULL);
break;
case emSessionType_SayBye:
strncpy(l_cPrintData, "Moudule_Say=>Bye, main\n");
//调用main传过来的函数指针,主动发“Bye, main”消息给main
m_pCallBack(emSessionType_SayBye, l_cPrintData, NULL);
break;
default:
break;
}//end switch(m_=_iPrintType)
m_iSessionType++;
if(m_iSessionType > emSessionType_SayBye )
{
m_iSessionType = emSessionType_SayHallo;
}//end if(emSessionType_SayBye > emSessionType_SayBye )
}//end while(1)
}//void vMouduleAPI_start_run()
3、main主函数功能源码实现
/******************main.c**********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "moudule_api.h"
//主函数的回调函数
void vMainAPI_CallBackFun(int p_iType, char *p_cData, void *userParam)
{ //回调函数不能做占用时间太长的操作,这里做一下数据拷贝,或者直接打印也行,不能加sleep函数
printf(“p_iType:%d, p_cData:%s\n, p_iType, p_cData);
}
void main()
{
//注册回调函数,将函数指针传给模块moudule
vCommom_CallBackEventFun(vMainAPI_CallBackFun);
while(1)
{
usleep(1000);
}//end while(1)
return;
}