回调函数就是通过函数指针调用函数。如果把函数的指针或者地址作为参数传递给另一个参数,当这个指针被用来调用其所指向的函数时,那么这就是一个回调的过程,这个被回调的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或者条件发生时由另外的一方调用的,用于对该事件或者条件进行响应。回调函数就是在两个独立函数或者独立类通信的通道。
对普通函数的调用:调用程序发出对普通函数的调用后,程序执行立即转向被调用函数执行,直到被调用函数执行完毕后,再返回调用程序继续执行。从发出调用的程序的角度看,这个过程为“调用–>等待被调用函数执行完毕–>继续执行”。
对回调函数调用:调用程序发出对回调函数的调用后,不等函数执行完毕,立即返回并继续执行。这样,调用程序执和被调用函数同时在执行。当被调函数执行完毕后,被调函数会反过来调用某个事先指定函数,以通知调用程序:函数调用结束。这个过程称为回调(Callback),这正是回调函数名称的由来。
两者实现上的区别:
(1) 同步回调:把函数b传递给函数a。执行a的时候,回调了b,a要一直等到b执行完才能继续执行;
(2) 异步回调:把函数b传递给函数。执行a的时候,回调了b,然后a就继续往后执行,b独自执行。
// C代码实现的同步回调函数
#include
#include
// C函数:回调函数
int RemoteControl(char *actions[], int actions_len){
printf("C函数被调用. ==> 你朋友通过你开的 ***远程控制*** 操作你的电脑.\n");
for(int i = 0; i < actions_len; i++){
printf(">> %s\n", actions[i]);
}
printf("C函数返回. ==> 处理完毕,退出远程的使用.\n");
return 0;
}
// B函数
int YourFriend(int rc(char *actions[], int actions_len)){
// actions是提供的一些动作
char *actions[] = {"右键计算机",
"选择属性",
"选择高级系统设置",
"... ..."
};
printf("B函数被调用. ==> 你朋友收到你的求助.\n");
rc(actions, 4); // 回调函数的执行
printf("B函数返回. ==> 你朋友向你反馈处理结果.\n");
return 0;
}
// A函数
int You(){
printf("A函数启动. ==> 你用电脑,遇到了问题.\n");
printf("A函数调用B函数. ==> 你向你朋友发起求助,同时提供 ***远程控制*** 给他.\n");
YourFriend(RemoteControl);
printf("A函数返回. ==> 你出门办事.\n");
return 0;
}
int main(){
char *msg[] = {"Hello", "World"};
You();
return 0;
}
程序运行输出结果如下
A函数启动. ==> 你用电脑,遇到了问题.
A函数调用B函数. ==> 你向你朋友发起求助,同时提供 ***远程控制*** 给他.
B函数被调用. ==> 你朋友收到你的求助.
C函数被调用. ==> 你朋友通过你开的 ***远程控制*** 操作你的电脑.
>> 右键计算机
>> 选择属性
>> 选择高级系统设置
>> ... ...
C函数返回. ==> 处理完毕,退出远程的使用.
B函数返回. ==> 你朋友向你反馈处理结果.
A函数返回. ==> 你出门办事.
一个疑问:同步回调和普通函数的调用在栈上的执行顺序有什么区别?
异步回调必定是多线程或者多进程的,不可能是单线程或者单进程的。
程序实例1:
#include
#include
#include
#include
/*C(回调)函数*/
int remote_control(char *actions[], int actions_len){
printf("C函数被调用. ==> 你朋友通过你开的 ***远程控制*** 操作你的电脑.\n");
for(int i = 0; i < actions_len; i++){
printf(">> %s\n", actions[i]);
}
printf("C函数返回. ==> 处理完毕,退出远程的使用.\n");
return 0;
}
/*B函数*/
int your_friend(int rc(char *actions[], int actions_len)){
char *actions[] = {"右键计算机",
"选择属性",
"选择高级系统设置",
"... ..."
};
printf("B函数被调用. ==> 你朋友收到你的求助.\n");
rc(actions, 4);
printf("B函数返回. ==> 你朋友向你反馈处理结果.\n");
pthread_exit(0);
}
/*A函数*/
int you(){
printf("A函数启动. ==> 你用电脑,遇到了问题.\n");
printf("A函数调用B函数. ==> 你向你朋友发起求助,同时提供 ***远程控制*** 给他.\n");
pthread_t id;
int thread_ret;
thread_ret = pthread_create(&id, NULL, (void *)your_friend, remote_control);
if(thread_ret){
printf("Create pthread error!");
return -1;
}
pthread_detach(id);
printf("A函数返回. ==> 你出门办事.\n");
//为了在标准输出看到B函数打印的信息,先不返回.
sleep(3);
return 0;
}
int main(void){
char *msg[] = {"Hello", "world"};
you();
return 0;
}
// 另一种传参方式
#include
#include
#include
#include
struct callbackArgs{
int (*callback_fun)(char *actions[], int actions_len);
} callback_args;
/*C(回调)函数*/
int remote_control(char *actions[], int actions_len){
printf("C函数被调用. ==> 你朋友通过你开的 ***远程控制*** 操作你的电脑.\n");
for(int i = 0; i < actions_len; i++){
printf(">> %s\n", actions[i]);
}
printf("C函数返回. ==> 处理完毕,退出远程的使用.\n");
return 0;
}
/*B函数*/
int your_friend(struct callbackArgs *input_function){
char *actions[] = {"右键计算机",
"选择属性",
"选择高级系统设置",
"... ..."
};
printf("B函数被调用. ==> 你朋友收到你的求助.\n");
input_function->callback_fun(actions, 4);
printf("B函数返回. ==> 你朋友向你反馈处理结果.\n");
pthread_exit(0);
}
/*A函数*/
int you(){
printf("A函数启动. ==> 你用电脑,遇到了问题.\n");
printf("A函数调用B函数. ==> 你向你朋友发起求助,同时提供 ***远程控制*** 给他.\n");
pthread_t id;
int thread_ret;
callback_args.callback_fun = remote_control;
thread_ret = pthread_create(&id, NULL, (void *)your_friend, &callback_args);
if(thread_ret){
printf("Create pthread error!");
return -1;
}
pthread_detach(id);
printf("A函数返回. ==> 你出门办事.\n");
//为了在标准输出看到B函数打印的信息,先不返回.
sleep(3);
return 0;
}
int main(void){
you();
return 0;
}
上述程序中,A函数相当于应用者;C函数是A函数创建的,但是并不在A函数中执行,而是作为回调函数向底层进行注册;B函数是底层的函数。
程序实例2:
假设有这样一个任务,A是底层,其产生的数据要给应用者B去使用,采用异步回调机制实现如以下两端程序所示:
A.cpp
//-----------------------底层实现A-----------------------------
typedef void (*pcb)(int a); //函数指针定义,后面可以直接使用pcb,方便
typedef struct parameter{
int a ;
pcb callback;
}parameter;
void* callback_thread(void *p1)//此处用的是一个线程
{
//do something
parameter* p = (parameter*)p1 ;
while(1)
{
printf("GetCallBack print! \n");
sleep(3);//延时3秒执行callback函数
p->callback(p->a);//函数指针执行函数,这个函数来自于应用层B
}
}
//留给应用层B的接口函数
extern SetCallBackFun(int a, pcb callback)
{
printf("SetCallBackFun print! \n");
parameter *p = malloc(sizeof(parameter)) ;
p->a = 10;
p->callback = callback;
//创建线程
pthread_t thing1;
pthread_create(&thing1,NULL,callback_thread,(void *) p);
pthread_join(thing1,NULL);
}
————————————————
版权声明:本文为CSDN博主「夏菠」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xiabodan/article/details/47999411
上面的代码就是底层接口程序员A写的全部代码,留出接口函数SetCallBackFun即可
下面再实现应用者B的程序,B负责调用SetCallBackFun
函数,以及增加一个函数,并将此函数的函数指针通过SetCallBackFun(int a, pcb callback)
的第二个参数pcb callback
传递下去。
B.cpp
//-----------------------应用者B-------------------------------
void fCallBack(int a) // 应用者增加的函数,此函数会在A中被执行
{
//do something
printf("a = %d\n",a);
printf("fCallBack print! \n");
}
int main(void)
{
SetCallBackFun(4,fCallBack);
return 0;
}
————————————————
版权声明:本文为CSDN博主「夏菠」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xiabodan/article/details/47999411