同步回调函数和异步回调函数
回调函数
回调函数一般是在封装接口的时候,回调显得特别重要,我们首先假设有两个程序员在写代码,A程序员写底层驱动接口,B程序员写上层应用程序,然而此时底层驱动接口A有一个数据d需要传输给B,此时有两种方式:
1.A将数据d存储好放在接口函数中,B自己想什么时候去读就什么时候去读,这就是我们经常使用的函数调用,此时主动权是B。
2.A实现回调机制,当数据变化的时候才将通知B,你可以来读取数据了,然后B在用户层的回调函数中读取速度d,完成OK。此时主动权是A。
很明显第一种方法太低效了,B根本就不知道什么时候该去调用接口函数读取数据d。而第二种方式由于B的读取数据操作是依赖A的,只有A叫B读数据,那么B才能读数据。也即是实现了中断读取。
那么回调是怎么实现的呢,其实回调函数就是一个通过函数指针调用的函数。如果用户层B把函数的指针(地址)作为参数传递给底层驱动A,当这个指针在A中被用为调用它所指向的函数时,我们就说这是回调函数。
注意:是在A中被调用,这里看到尽管函数是在B中,但是B却不是自己调用这个函数,而是将这个函数的函数指针通过A的接口函数传自A中了,由A来操控执行,这就是回调的意义所在。
同步回调和异步回调
首先,理解几个概念:
1.回调可以是同步也可以是异步
2.同步可以是单线程也可以是多线程
异步必须是多线程或多进程(每个进程可以是单线程) ==> 换句话说,异步必须依靠多线程或多进程才能完成
同步回调:把函数b传递给函数a。执行a的时候,回调了b,a要一直等到b执行完才能继续执行;
异步回调:把函数b传递给函数a。执行a的时候,回调了b,然后a就继续往后执行,b独自执行。
直接看例子
A.h
1 2 3 4 5 6 7 | #ifndef A_H #define A_H typedef void (*pcb)( int a); //函数指针定义,后面可以直接使用pcb,方便 void SetCallBackFun( int a, pcb callback); #endif |
同步回调
synA.c
1 2 3 4 5 6 7 8 9 10 11 | #include <stdio.h> #include "A.h" //-----------------------底层实现A----------------------------- //留给应用层B的接口函数 void SetCallBackFun( int a, pcb callback) { printf ( "A:start\n" ); callback(a); printf ( "A:end\n" ); } |
synB.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "A.h" //-----------------------应用者B------------------------------- void fCallBack( int a) // 应用者增加的函数,此函数会在A中被执行 { //do something printf ( "B:start\n" ); printf ( "a = %d\n" ,a); sleep(5); printf ( "B:end\n" ); } int main( void ) { SetCallBackFun(4,fCallBack); return 0; } |
异步回调
asynA.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include "A.h" //-----------------------底层实现A----------------------------- typedef struct parameter{ int a ; pcb callback; }parameter; void * callback_thread( void *p1) //此处用的是一个线程 { //do something parameter* p = (parameter*)p1 ; sleep(5); p->callback(p->a); //函数指针执行函数,这个函数来自于应用层B } //留给应用层B的接口函数 void SetCallBackFun( int a, pcb callback) { printf ( "A:start\n" ); parameter *p = malloc ( sizeof (parameter)) ; p->a = a; p->callback = callback; //创建线程 pthread_t pid; pthread_create(&pid,NULL,callback_thread,( void *) p); printf ( "A:end\n" ); //阻塞,等待线程pid结束,才往下走 pthread_join(pid,NULL); } |
asynB.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "A.h" //-----------------------应用者B------------------------------- void fCallBack( int a) // 应用者增加的函数,此函数会在A中被执行 { //do something printf ( "B:start\n" ); printf ( "a = %d\n" ,a); sleep(5); printf ( "B:end\n" ); } int main( void ) { SetCallBackFun(4,fCallBack); return 0; } |
运行结果比较:
同步回调 | 异步回调 |
A:start B:start a = 4 B:end A:end |
A:start A:end B:start a = 4 B:end |
由执行结果可以看出:同步回调,A需要等待B执行完成才能执行A剩余的操作;异步回调,A刚执行B,不必等待B结束,就执行A剩余的操作,之后B的操作也随之end。
__EOF__

本文链接:https://www.cnblogs.com/still-smile/p/12048078.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架