异步回调的实现依赖于多线程或者多进程

软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知

在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类成为回调类,回调类的对象成为回调对象。对于象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;
}

异步实现方式一:异步回调相关推荐

  1. asio boost 异步错误处理_boost::ASIO的同步方式和异步方式

    http://blog.csdn.net/zhuky/article/details/5364574 http://blog.csdn.net/zhuky/article/details/536468 ...

  2. 异步消息的传递-回调机制

    1 什么是回调 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用.回调和异步调用.同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用:回调是一种双向 ...

  3. 【javascript】异步编年史,从“纯回调”到Promise

    异步和分块--程序的分块执行   一开始学习javascript的时候, 我对异步的概念一脸懵逼, 因为当时百度了很多文章,但很多各种文章不负责任的把笼统的描述混杂在一起,让我对这个 JS中的重要概念 ...

  4. java异步处理同步化_java 异步查询转同步多种实现方式:循环等待,CountDownLatch,Spring EventListener,超时处理和空循环性能优化...

    异步转同步 业务需求 有些接口查询反馈结果是异步返回的,无法立刻获取查询结果. 正常处理逻辑 触发异步操作,然后传递一个唯一标识. 等到异步结果返回,根据传入的唯一标识,匹配此次结果. 如何转换为同步 ...

  5. JS异步:执行原理与回调

    JS异步:执行原理与回调 一.JS异步的执行原理 二.JS异步中的回调 一.JS异步的执行原理   我们知道JavaScript是单线程的,而浏览器是多线程的.单线程执行任务需要一个个排队进行,假如一 ...

  6. JS 异步编程的解决方案,以及回调地狱的解决方案

    1.回调函数 回调函数是异步编程最基本的方法. 所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,再调用这个函数. fs.readFile('/etc/fstab', ...

  7. Java 异步编程 (5 种异步实现方式详解)

    同步操作如果遇到一个耗时的方法,需要阻塞等待,那么我们有没有办法解决呢?让它异步执行,下面我会详解异步及实现 @mikechen 目录 什么是异步? 一.线程异步 二.Future异步 三.Compl ...

  8. FPGA逻辑设计回顾(6)多比特信号的CDC处理方式之异步FIFO

    文章目录 前言 异步FIFO的概念 异步FIFO为什么可以解决CDC问题? 异步FIFO的RTL实现 参考资料 前言 异步FIFO是处理多比特信号跨时钟域的最常用方法,简单来说,异步FIFO是双口RA ...

  9. Java8新的异步编程方式 CompletableFuture(三)

    前面两篇文章已经整理了CompletableFuture大部分的特性,本文会整理完CompletableFuture余下的特性,以及将它跟RxJava进行比较. 3.6 Either Either 表 ...

  10. 【Kotlin 协程】Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )

    文章目录 一.使用 Flow 异步流持续获取不同返回值 二.Flow 异步流获取返回值方式与其它方式对比 三.在 Android 中 使用 Flow 异步流下载文件 一.使用 Flow 异步流持续获取 ...

最新文章

  1. [zz]libvirt中CPU和内存的细粒度管理机制
  2. asp.net中此页的状态信息无效,可能已损坏的解决之道
  3. 图形学教程Lecture 13: RayTracing1(Whitted-Style Ray Tracing)知识点总结
  4. 三菱q系列plc连接电脑步骤_三菱Q系列PLC与三菱变频器的CC-link通讯技术(我的学习笔记)...
  5. python3动态加载模块的方法实现
  6. 百度地图与谷歌地图 (常识、区别,更倾向于使用百度地图,纠错信息比谷歌多)...
  7. django多语言支持
  8. Python字符串类型:字符串索引、字符串切片、字符串format()方法格式化、字符串操作符、字符串处理函数
  9. Gym 101246G Revolutionary Roads
  10. Mybatis3 最简例子
  11. layer normalization 缺点_优缺点并存的星越,用车感受还是不错的!
  12. 计算机win7截长屏,电脑截长图【应对法子】
  13. [转]各种配置管理工具的比较
  14. struts1.x 升级到struts2的几点问题
  15. JTT808、JTT1078、TJSATL主动安全踩坑记录
  16. android:viewpager+photoview实现图片查看器
  17. html 字体居中 font,CSS字体(font)
  18. 颈椎病及腰椎间盘突出病因病理
  19. Java与WCF交互(一)补充:用WSImport生成WSDL的Java客户端代码
  20. Quick BI可以帮助我们大大提升响应速度

热门文章

  1. Python常用库1:collections,容器数据类型
  2. springcloud学习(七)-Sidecar(多语言支持)
  3. 装修房子的过程就像产品经理做产品一样
  4. [022] Android、iPhone和Java三个平台一致的加密工具
  5. mysql的count函数类型是什么意思_MySQL中的COUNT函数,你理解多少
  6. AI之机器翻译及相关技术
  7. 63.Isaac教程--Flatsim
  8. TODO:火热的集福,我这样看
  9. negative和passive的反义词_negative 和 passive的区别?
  10. 微信小程序 - 返回前一个页面时,执行前一个页面的函数方(wx.navigateBack 返回后,执行上一页的某个函数方法刷新数据)回前一个页面时,执行前一个页面的函数方法。支持改变 data 数据。