01
最初的梦想
回调函数callback,也叫:call-after。相对付急速调用而言,它意思便是转头再调用,或者叫:过一会再调用、事后调用。

急速调用:这和编写普通函数一下,程序员在代码中写上一个函数,通报好参数,如果不出意外的话,CPU在运行到该行代码后,就会作函数调用,这种情形很直不雅观,也非常好理解。
转头调用:或者叫事后调用(whatever,大家可以起一个更形象的名字),利用的场景轻微繁芜一点:每每是一个函数,我们无法确定它的调用机遇,例如:我们须要在用户点击一个按钮后,弹出一个对话框。但用户何时点击按钮是无法预测的!
以是,弹出对话框的函数,最好是在GUI线程里面,由按钮相应函数onClick中调用:
//UI threadvoid onClick(){ openDialog();}
02
变味的回调
当然,这并不能让callback变得无法取代,真正让callback变得有点无法避免的缘故原由是:函数onClick也不知道要调用哪个详细的函数。例如:用户点击按钮后,可能是须要弹出一个对话框,也可能是须要点亮一个LED,也可能是。。。不同的处理方法,每每对应着不同的处理函数。
这样,我们在为onClick准备回调函数的时候,每每是不愿定的,为了应对这种变革,我们每每会预先设定一个转头再调用的函数,然后再交给用户交互(UI)线程决定什么时候调用:
void openDialog(){}void openLED(){}//Set callbackauto callback = openDialog;//or openLEDvoid onClick(){ callback(); //call callback}//UI threadvoid UIthread(){ ... onClick(); ...}
当然,最常见的形式,可能是这样的:把回调函数,以参数的形式通报给设置函数:
void onClick(auto callback)//auto是函数指针类型{ callback();}//UI threadvoid UIthread(){ ... onClick(openLED);//Set/Call callback ...}
这样,就让onClick函数具备了事后处理任何事情的能力。须要处理什么事情,就通报该事情的处理函数地址就好,当然,如果胆敢给个造孽地址的话,那segmentation fault也会如约而至。
这个时候,建议大家看一下文章《CPU眼里的:函数指针》,它是回调函数可以成立的技能根本。
当然,这种利用场景下,已经跟callback的字面意思相差甚远了。倒是让callback差点成为了“函数指针”的代名词。但习气的力量是巨大的,以是callback也就一贯这么叫下去了。
03
总结
本日我们再谈论回调函数的时候,每每须要具备两个条件:事前准备和事后调用。也便是事前准备:调用哪个函数;和在等某件事情发生后,由事后处理函数,调用事前准备好的函数。利用回调函数的地方,每每会涉及到两个线程,一个是事前准备的线程,也便是预设回调函数的线程;其余一个是事后处理线程,也便是真正调用回调函数的线程。函数指针,也便是被调函数的内存首地址,它每每作为一个函数参数,通报给事后处理函数备用。不同的参数,每每对应着不同的被调函数。这种设计办法,让被调函数的选择面极广,可以根据不同的情形,准备不同的回调函数。这让程序变得更加灵巧、有弹性。末了,回调函数,撕裂了代码的逻辑,每每一到函数指针,代码的逻辑线就断了。由于,事前准备回调函数的线程逻辑,跟事后调用回调函数的线程逻辑,每每是两个不同的故事。