异步实现方式一:异步回调
异步回调的实现依赖于多线程或者多进程
软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。
在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类成为回调类,回调类的对象成为回调对象。对于象C++这些兼容了过程特性的对象语言,不仅提供了回调对象、回调方法等特性,也能兼容过程语言的回调函数机制。
Windows平台的消息机制也可以看作是回调的一种应用,我们通过系统提供的接口注册消息处理函数(即回调函数),从而实现接收、处理消息的目的。由于Windows平台的API是用C语言来构建的,我们可以认为它也是回调函数的一个特例。
2 过程语言中的回调(C)
回调的应用常见场景:用户在断线重连时,login_user类需要调用mgr类中的函数B去获取登陆玩家的信息,那么函数B需要login_user类提供一个usid,login_user类则需要提供一个callback函数来接收mgr类中函数B所提供的信息,callback函数处理login_user类中的业务。
简单来讲就是:把需要访问其他函数数据的函数(即callback函数)作为实参传递,callback函数处理回原逻辑
2.1 函数指针
回调在C语言中是通过函数指针来实现的,通过将回调函数的地址传给被调函数从而实现回调。因此,要实现回调,必须首先定义函数指针,请看下面的例子:
1
2
|
void Func(char *s);// 函数原型
void (*pFunc) (char *);//函数指针
|
可以看出,函数的定义和函数指针的定义非常类似。
一般为了简化函数指针类型的变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。
1
|
typedef void(*pcb)(char *);
|
回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。
同步回调:
#include <iostream> typedef void (*Fun)(int);//定义一个函数指针类型
Fun p = NULL;//用Fun定义一个变量p,它指向一个返回值为空参数为int的函数 void caller(Fun pCallback)
{ p = pCallback; printf(" in function \n");//达成某一条件后,通过名片(函数指针p),传回结果 int result = 1; (*p)(result);
} void callback(int a)//回调函数
{ std::cout << "callback result = " << a << std::endl;
} int main(int argc, char* argv[])
{ caller(callback); printf("out function \n");//同步的回调getchar(); return 0;
}
2.2 参数传递规则
到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几种调用规范。如在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。C++ Builder也支持_fastcall调用规范。调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。
将调用规范看成是函数类型的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。例如:
1
2
3
4
5
6
|
// 被调用函数是以int为参数,以int为返回值
__stdcall int callee(int);
// 调用函数以函数指针为参数
void caller( __cdecl int(*ptr)(int));
// 在p中企图存储被调用函数地址的非法操作
__cdecl int(*p)(int) = callee; // 出错
|
指针p和callee()的类型不兼容,因为它们有不同的调用规范。因此不能将被调用者的地址赋值给指针p,尽管两者有相同的返回值和参数列
异步回调理解版例子:
在A类中定义一个callback回调函数作为返回A类所处线程的接口,然后通过call函数去创建新的线程2并运行,线程2中调用b类的answer函数,answer函数把回调函数指针callback作为实参,当前call函数在创建完线程后是不阻塞的,可以继续运行dosomething函数,。 。。在线程2中的answer函数通过调用实参callback函数指针重新回到线程1。
/** * 这是一个回调接口,里面定义的方法就是回调函数 */
public interface CallBack { /** * 这是一个回调函数,用于回答者B知道答案后给提问者A回电话,并告知提问者A答案是什么 * 这个回电话的方式callBack是提问者A确定的,所以这个方法的实现类是A类 * 这个回电话的内容result是回答者B提供的,所以这个变量的值是在B类中确定的 */ public void callBack(String result);
}
[java] view plain copy
/** * 提问者A类 */
public class A implements CallBack{ /** * 提问者A是知道回答者B的联系方式的 * 这里以一个B类引用代表,并在构造方法中传入B实例对象 */ private B b; public A(B b){ this.b = b; } /** * 提问者A向回答者B打电话提问题 * 这里以一个call方法表示,并把问题参数传入 */ public void call(final String question){ /** * 建立提问者A线程,与回答者B线程结合,构成一个异步的环境 */ new Thread(new Runnable() { @Override public void run() { /** * B接电话,听问题 * 这里以调用回答者B的answer方法表示,传入回调方法类参数、问题参数,以表示谁打的电话,问啥了 * 因为A类实现了CallBack接口,所以A类就是回调方法类,回调方法类实现了回调方法 */ b.answer(A.this, question); } }).start(); /** * 提问者提完问,去干别事情 */ doOtherThing(); } public void doOtherThing(){ System.out.println("我是提问者A,我问完问题就去干别的事情了!"); } /** * 刚刚说到,这个回电话的方式callBack是提问者A确定的,所以这个方法的实现类是A类 * 所以这里实现回调方法,代表回复的方法是回电话,由回答者B调用 */ @Override public void callBack(String result) { System.out.println("B调用A定义的回调函数:回答者B告诉提问者A,问题的答案是:"+ result); } }
[java] view plain copy
/** * 回答者B类 */
public class B { /** * 回答者B接电话,听问题 这里以调用回答者B的answer方法表示,传入回调方法类、问题参数,以表示谁打的电话,问啥了 */ public void answer(CallBack callBack, String question) { System.out.println("A调用B的接电话方法:我是回答者B,提问者A问的问题是:" + question); /** * 模拟回答者B先忙自己的事 */ System.out.println("我是回答者B,我接完电话先去忙我自己的事!"); for (int i = 0; i < 100000; i++) { } String result = "2"; System.out.println("我是回答者B,我知道了答案是:" + result); /** * 调用回调函数,打电话告知A答案是什么 */ callBack.callBack(result); }
}
[java] view plain copy
/** * 场景测试类 */
public class test { public static void main(String args[]){ /** * 实例化回答者B */ B b = new B(); /** * 实例化提问者A */ A a = new A(b); /** * A向B提问,开始 */ a.call("1 + 1 = ?"); }
}
异步回调: |
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER#include <windows.h>
#else#include <pthread.h>
#endif#ifdef _MSC_VER#define mysleep(n) Sleep(n)
#else#define mysleep(n) sleep(n/1000)
#endifusing namespace std;class xiabo_C{
public:xiabo_C():a(10),d(8){printf("I am xiabo_C() function\n");}static int sfunc(); //静态成员函数也遵循public,private,protected访问规则int func(void);public:int a;static int b ; //此处不能初始化static const int c = 9;//只有静态常量才能直接初始化const int d;
};int xiabo_C::b = 11; //静态成员变量的初始化只能这样,不能在构造中初始化int xiabo_C::sfunc(){ //!!!静态成员函数在类外部实现时,千万不要加static,不要写成了static int sfunc(){},这是内外部的静态C函数//xiabo::a = 11; //error 静态成员函数不能应用非静态成员xiabo_C::b = 12;printf("I am static member function,b = %d\n",xiabo_C::b );return 0;
}
static int sfunc1(){printf("I am static function, not member function \n" );return 0;
}
int xiabo_C::func(void){xiabo_C::b = 12;xiabo_C::sfunc();sfunc1();return 0;
}
void test_statichunc(void){xiabo_C xiabo;xiabo.func();xiabo_C::sfunc(); //静态成员函数是类的,不是某个对象的,引用必须通过类名来访问}
//-------------
class xiabo2_C{
public:typedef int (*pcb)(int a);typedef struct parameter{int a ;pcb callback;}parameter; xiabo2_C():m_a(1){}//普通函数void GetCallBack(parameter* p) // 写回调者实现的回调函数{m_a = 2;//do somethingwhile(1){printf("GetCallBack print! \n");mysleep(2000);p->callback(p->a);}}int SetCallBackFun(int a, pcb callback){printf("SetCallBackFun print! \n");parameter *p = new parameter ; p->a = 10;p->callback = callback;GetCallBack(p);return 0;}public:int m_a;
};class xiabo2Test_C{
public:xiabo2Test_C():m_b(1){}static int fCallBack(int a) // 应用者实现的回调函数,静态成员函数,但是不能访问类中非静态成员了,破坏了类的结构{//do something//m_b = a; // 不能访问类中非静态成员了,破坏了类的结构,应用者使用很麻烦printf("a = %d\n",a);printf("fCallBack print! \n");return 0;}
public:int m_b;
};//-------------------
template<typename Tobject,typename Tparam>
class xiabo3_C{typedef void (Tobject::*Cbfun)(Tparam* );
public:bool Exec(Tparam* pParam);void Set(Tobject *pInstance,Cbfun pFun,Tparam* pParam);private:Cbfun pCbfun;Tobject* m_pInstance;
};template<typename Tobject,typename Tparam>
void xiabo3_C<Tobject,Tparam>::Set(Tobject *pInstance,Cbfun pFun,Tparam* pParam){printf("Set print!\n");m_pInstance = pInstance;(pInstance->*pFun)(pParam); //可以直接在这里回调传过来的函数指针pCbfun = pFun;
}
template<typename Tobject,typename Tparam>
bool xiabo3_C<Tobject,Tparam>::Exec(Tparam* pParam){printf("Exec print!\n");(m_pInstance->*pCbfun)(pParam);//也可以在这里回调传过来的函数指针return true;
}class xiabo3Test_C{
public:xiabo3Test_C():m_N(13){}void fCallBack(int *p){printf("fCallBack : Sum = m_N + *p = %d\n",*p + m_N);printf("fCallBack print! I am a member function! I can access all the member ,HaHa...\n");}private:int m_N;};//--------------
//类中定义线程,并实现回调
class xiabo4_C{
public:struct ThreadParam{xiabo4_C* pthis;int a ;int b ;};//根据线程参数自定义结构public:xiabo4_C():m_N(1){}void print(void){printf("print : m_N = %d \n",m_N);}//静态实现void CreatAlgorithmThread(void);static void *funThreadAlgorithm(void* p); //静态成员函数实现线程Wrapper//非静态实现void CreatAlgorithm2Thread(int a ,int b);static void *funThreadAlgorithm2(void* param); //非静态成员函数实现线程Wrappervoid ThreadFunc(int a ,int b){printf("ThreadFunc : I am ThreadFunc,I am a member function! I can access all the member ,HaHa...\n");printf("ThreadFunc : m_N = %d \n",m_N);}private:int m_N;
};void xiabo4_C::CreatAlgorithmThread(void){ //静态实现
#ifdef _MSC_VERHANDLE handle1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)funThreadAlgorithm,0,0,NULL); CloseHandle(handle1);
#elsepthread_t thing1;pthread_create(&thing1,NULL,&funThreadAlgorithm,(void *) 0);pthread_join(thing1,NULL);
#endif
}
void* xiabo4_C::funThreadAlgorithm(void* p){while(1){mysleep(2000);printf("I am a static meeber function! I can not access the member\n");}
}void xiabo4_C::CreatAlgorithm2Thread(int a ,int b){ThreadParam* p = new ThreadParam;p->pthis = this;p->a = a;p->b = b;
#ifdef _MSC_VERHANDLE handle2 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)funThreadAlgorithm2,p,0,NULL); CloseHandle(handle2);
#elsepthread_t thing1;pthread_create(&thing1,NULL,&funThreadAlgorithm2,(void *) p);pthread_join(thing1,NULL);
#endif
}
void* xiabo4_C::funThreadAlgorithm2(void* param){ThreadParam* p = (ThreadParam*)param;printf("I am a static meeber function! I can not access the member\n");printf("But I can call a member func ,I can instigate ThreadFunc ,ThreadFunc can access all member\n");printf("ThreadParam p->a = %d, p->b = %d \n",p->a,p->b);p->pthis->ThreadFunc(p->a,p->b);return 0;
}//--------------
//类中定义线程,并实现回调
//A程序员
template<typename Tobject,typename Tparam>
class xiabo5_C{
public:struct ThreadParam{xiabo5_C* pthis;Tparam a ;};//根据线程参数自定义结构typedef void (Tobject::*Cbfun)(Tparam );
public:xiabo5_C():m_N(1){printf("xiabo5_C : xiabo5_C()\n");}void print(void){printf("print : m_N = %d \n",m_N);}//非静态实现void CreateCallbackThread(Tobject *pInstance,Cbfun pFun,Tparam a );static void* funCallbackThread(void* param); //非静态成员函数实现线程Wrappervoid ThreadFunc(Tparam a ); //线程执行函数private:int m_N;Cbfun pCbfun;Tobject* m_pInstance;
};
template<typename Tobject,typename Tparam>
void xiabo5_C<Tobject,Tparam>:: CreateCallbackThread(Tobject *pInstance,Cbfun pFun,Tparam a ){ThreadParam* p = new ThreadParam;p->pthis = this;p->a = a;m_pInstance = pInstance;pCbfun = pFun;#ifdef _MSC_VERHANDLE handle2 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)funCallbackThread,p,0,NULL); CloseHandle(handle2);
#elsepthread_t thing1;pthread_create(&thing1,NULL,&funCallbackThread,(void *) p);//pthread_join(thing1,NULL); //这儿不能阻塞
#endif
}
template<typename Tobject,typename Tparam>
void* xiabo5_C<Tobject,Tparam>::funCallbackThread(void* param){ThreadParam* p = (ThreadParam*)param;printf("I am a static meeber function! I can not access the member\n");printf("But I can call a member func ,I can instigate ThreadFunc ,ThreadFunc can access all member\n");printf("ThreadParam p->a = %d\n",p->a);p->pthis->ThreadFunc(p->a);return 0;
}
template<typename Tobject,typename Tparam>
void xiabo5_C<Tobject,Tparam>::ThreadFunc(Tparam a ){printf("ThreadFunc : I am ThreadFunc,I am a member function! I can access all the member ,HaHa...\n");printf("ThreadFunc : m_N = %d \n",m_N);while(1){mysleep(2000);(m_pInstance->*pCbfun)(a);}
}
//B程序员
class xiabo5Test_C{
public:xiabo5Test_C():m_N(55){}void fCallBack(int p){printf("fCallBack : Sum = m_N + *p = %d\n",p + m_N);printf("fCallBack print! I am a member function! I can access all the member ,HaHa...\n");}
public:private:int m_N;
};int main(void ){//测试静态成员函数//test_statichunc();//测试静态成员函数,用于回调//xiabo2_C xiabo2;//xiabo2.SetCallBackFun(5,xiabo2Test_C::fCallBack);//测试非静态成员函数,用于回调,good//xiabo3_C<xiabo3Test_C,int> xiabo3;//xiabo3Test_C xiabo3Test;//int p = 13;//xiabo3.Set(&xiabo3Test,&xiabo3Test_C::fCallBack,&p); ////xiabo3.Exec(&p);//类中定义线程//xiabo4_C xiabo4;//xiabo4.CreatAlgorithm2Thread(1,2);//类中定义线程,并实现回调xiabo5_C<xiabo5Test_C,int> xiabo5;xiabo5Test_C xiabo5Test;int p = 45;xiabo5.CreateCallbackThread(&xiabo5Test,&xiabo5Test_C::fCallBack,p);xiabo5_C<xiabo5Test_C,int> xiabo51;xiabo5Test_C xiabo5Test1;int p1 = -45;xiabo51.CreateCallbackThread(&xiabo5Test1,&xiabo5Test_C::fCallBack,p1);//getchar();return 0;
}
异步实现方式一:异步回调相关推荐
- asio boost 异步错误处理_boost::ASIO的同步方式和异步方式
http://blog.csdn.net/zhuky/article/details/5364574 http://blog.csdn.net/zhuky/article/details/536468 ...
- 异步消息的传递-回调机制
1 什么是回调 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用.回调和异步调用.同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用:回调是一种双向 ...
- 【javascript】异步编年史,从“纯回调”到Promise
异步和分块--程序的分块执行 一开始学习javascript的时候, 我对异步的概念一脸懵逼, 因为当时百度了很多文章,但很多各种文章不负责任的把笼统的描述混杂在一起,让我对这个 JS中的重要概念 ...
- java异步处理同步化_java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring EventListener,超时处理和空循环性能优化...
异步转同步 业务需求 有些接口查询反馈结果是异步返回的,无法立刻获取查询结果. 正常处理逻辑 触发异步操作,然后传递一个唯一标识. 等到异步结果返回,根据传入的唯一标识,匹配此次结果. 如何转换为同步 ...
- JS异步:执行原理与回调
JS异步:执行原理与回调 一.JS异步的执行原理 二.JS异步中的回调 一.JS异步的执行原理 我们知道JavaScript是单线程的,而浏览器是多线程的.单线程执行任务需要一个个排队进行,假如一 ...
- JS 异步编程的解决方案,以及回调地狱的解决方案
1.回调函数 回调函数是异步编程最基本的方法. 所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,再调用这个函数. fs.readFile('/etc/fstab', ...
- Java 异步编程 (5 种异步实现方式详解)
同步操作如果遇到一个耗时的方法,需要阻塞等待,那么我们有没有办法解决呢?让它异步执行,下面我会详解异步及实现 @mikechen 目录 什么是异步? 一.线程异步 二.Future异步 三.Compl ...
- FPGA逻辑设计回顾(6)多比特信号的CDC处理方式之异步FIFO
文章目录 前言 异步FIFO的概念 异步FIFO为什么可以解决CDC问题? 异步FIFO的RTL实现 参考资料 前言 异步FIFO是处理多比特信号跨时钟域的最常用方法,简单来说,异步FIFO是双口RA ...
- Java8新的异步编程方式 CompletableFuture(三)
前面两篇文章已经整理了CompletableFuture大部分的特性,本文会整理完CompletableFuture余下的特性,以及将它跟RxJava进行比较. 3.6 Either Either 表 ...
- 【Kotlin 协程】Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )
文章目录 一.使用 Flow 异步流持续获取不同返回值 二.Flow 异步流获取返回值方式与其它方式对比 三.在 Android 中 使用 Flow 异步流下载文件 一.使用 Flow 异步流持续获取 ...
最新文章
- [zz]libvirt中CPU和内存的细粒度管理机制
- asp.net中此页的状态信息无效,可能已损坏的解决之道
- 图形学教程Lecture 13: RayTracing1(Whitted-Style Ray Tracing)知识点总结
- 三菱q系列plc连接电脑步骤_三菱Q系列PLC与三菱变频器的CC-link通讯技术(我的学习笔记)...
- python3动态加载模块的方法实现
- 百度地图与谷歌地图 (常识、区别,更倾向于使用百度地图,纠错信息比谷歌多)...
- django多语言支持
- Python字符串类型:字符串索引、字符串切片、字符串format()方法格式化、字符串操作符、字符串处理函数
- Gym 101246G	Revolutionary Roads
- Mybatis3 最简例子
- layer normalization 缺点_优缺点并存的星越,用车感受还是不错的!
- 计算机win7截长屏,电脑截长图【应对法子】
- [转]各种配置管理工具的比较
- struts1.x 升级到struts2的几点问题
- JTT808、JTT1078、TJSATL主动安全踩坑记录
- android:viewpager+photoview实现图片查看器
- html 字体居中 font,CSS字体(font)
- 颈椎病及腰椎间盘突出病因病理
- Java与WCF交互(一)补充:用WSImport生成WSDL的Java客户端代码
- Quick BI可以帮助我们大大提升响应速度
热门文章
- Python常用库1:collections,容器数据类型
- springcloud学习(七)-Sidecar(多语言支持)
- 装修房子的过程就像产品经理做产品一样
- [022] Android、iPhone和Java三个平台一致的加密工具
- mysql的count函数类型是什么意思_MySQL中的COUNT函数,你理解多少
- AI之机器翻译及相关技术
- 63.Isaac教程--Flatsim
- TODO:火热的集福,我这样看
- negative和passive的反义词_negative 和 passive的区别?
- 微信小程序 - 返回前一个页面时,执行前一个页面的函数方(wx.navigateBack 返回后,执行上一页的某个函数方法刷新数据)回前一个页面时,执行前一个页面的函数方法。支持改变 data 数据。