你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
这是一段在知乎上的回答。比较生动。
我想以我现有的知识,来表达我的理解。
一旦触发了与相应回调绑定的事件,main将通过委托中介去调用callback函数。
跟硬件中断有些像,将某个中断事件处理函数注册到中断中去,当该中断发生时(硬件触发),硬件根据注册表找到处理该中断事件的函数指针,并将其放入特定位置,通过代码取得该指针,然后去调用它(该中断事件的处理函数)(类比callback function)。
回调有什么用?
回调的精髓在于动态绑定。动态体现在,传递的是函数指针。绑定,说的是,与相应的事件绑定,只有该事件触发才回callback。
举个例子,假设,user连续按下A,B,C,D与ENTER共5个键时,处理key A需要较长的时间,则其他4个key事件会被保存在queue中,暂时无法被处理。如此时使用者等得不耐烦了,按了ESC想要跳出这个功能,则应用程序该如何应对??
在一般的设计架构中,整个硬件事件处理的流程中,应用程序完全无法插手,而OS也无法定义ESC key的意义是什么。所以在上述状况中,ESC key会被保存在queue中,要等到前5个key处理完后,应用程序才知道原来ESC key已经被按下了。Callback function可以用来解决整个问题,让应用程序设计的更有弹性。简单的说可以先对keyboerd driver注册处理ESC key的函数(即绑定ESC事件与它的处理函数)。则每当key事件发生时,keyboard driver除了执行原来的流程外,在某个阶段就会去调用应用程序注册的function,所以ESC key就可以被提前处理了。
程序代码段B-1
//define.h
//定义Key Callback Function的prototype
//
//传入一个int表示key的编号
//
typedef void (*key_callback) (int);
程序代码段B-2
//drv_key.c
//keyboard driver
//
#include <define.h>
//Global Variable
//
key_callback sys_key_callback = 0;
//Function : key_register_callback
//用途:让应用程序可以注册keyboard callback
//参数: 传入的新的Callback Function的指针
//
void key_register_callback(key_callback new_callback)
{
sys_key_callback = new_callback;
}
//Function: key_process_key_event
//处理key event, 中间回去调用sys_key_callback()
//
void key_process_key_event(int key)
{
...处理kev even
...
if(sys_key_callback != 0)//已经注册过Callback Function
sys_key_callback(key);//调用应用程序的Callback Function
...继续处理key event
...
}
程序代码段B-3
//application.c
//应用程序
//
//Function : app_ke_callback
//keyboard的Callback Function,当某个key事件发生时
//
void app_key_callback(int key)
{
if(key == KEY_ESC)
{
//处理ESC KEY
}
}
//Function : app_main
//应用程序的主程序,必须尽早注册key Callback Funtion
//
void app_main(void)
{
...
...
//注册key Callback Function
//
key_register_callback(app_key_callback);
...
...
}
从中,我们可以看出,对事件触发判断是通过 if (sys_key_callback != 0)代码来实现的,通过让CPU自己去查询判断(软终端)。这样,跟硬件中断就有明显差别了。