回调函数在异步编程中有着重要的作用,在接口编程应用广泛,实战中经常会注册一个回调函数来接收其他程序返回的数据,这样做的好处是调用者无需主动去获取被调用者的数据,仅仅需要回调,让被调用者去传送数据,这样就形成了回调,这是回调最常见的应用。
假设A是视频流数据,每隔一段时间会将数据传送给B,B有两种接收方式:
- A将视频数据存储好,提供接口,B根据自己的需求去调用,无需考虑时间,主动权在B。
- A利用回调机制,实现回调函数,当数据来临时通知B来取数据,B注册回调函数接收数据,这样主动权在A。
很显然第一种取数据的方式,由于B不知道数据何时来临比较低效,而第二种取数据方式A通知B来取数据,效率比较高,间接的实现了中断取数。
这里就用到了回调,B注册一个函数,将函数地址传给A,A中调用该地址获取到B注册的函数时,我们就称这个函数为回调函数。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
// A的实现,一般会隐藏
typedef void (*CallbackPtr)(int); //函数指针定义
typedef struct parameter{
int a ;
CallbackPtr callback;
}parameter;
// 创建实例
parameter ParaData;
void* callback_thread(void *p1)//此处用的是一个线程
{
//do something
// 循环改变p->a的值为为0 2 3 4 5 6 7 8 9 ,每隔3秒改变一次
parameter* p = (parameter*)p1 ;
while(1)
{
sleep(3);//延时3秒执行callback函数
p->callback(p->a);//函数指针执行函数,这个函数来自于应用层B
p->a = (p->a + 1) % 10;
}
}
void startup_app_A()
{
// 初始化为0
ParaData.a = 0;
CallbackPtr init_call_back;
ParaData.callback = init_call_back;
//创建线程
pthread_t thing1;
pthread_create(&thing1,NULL,callback_thread,(void *) &ParaData);
}
// 给B的接口,接收注册函数
extern void SetCallBackFun(CallbackPtr callback)
{
printf("SetCallBackFun print! \n");
ParaData.callback = callback;
}
// //-----------------------应用者B-------------------------------
void fCallBack(int a) // 应用者增加的函数,此函数会在A中被执行
{
//do something
printf("B得到A的数据 = %d\n",a);
}
int main(void)
{
// 启动A
startup_app_A();
SetCallBackFun(fCallBack);
// 主函数
while (1)
{
// std::cout << "main function" << std::endl;
printf("main function\n");
sleep(2);
}
return 0;
}
运行结果:
分析结果,可以看出A提供的数据会回调B,B会每隔一定的时间收到数据,完成回调,对于一般的编程会将A的操作封装起来,只提供以下接口和函数指针类型:
typedef void (*CallbackPtr)(int);
extern void SetCallBackFun(CallbackPtr callback);
这样B可以每次注册回调函数获取A传来的数据,如下:
void fCallBack(int a) // 应用者增加的函数,此函数会在A中被执行
{
//do something
printf("B得到A的数据 = %d\n",a);
}
主函数中调用:
SetCallBackFun(fCallBack);
这样就完成了一个C语言回调的异步编程。