您的位置:首页 > 其它

异步实现方式一:异步回调

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


在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类成为回调类,回调类的对象成为回调对象。对于象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语言中是通过函数指针来实现的,通过将回调函数的地址传给被调函数从而实现回调。因此,要实现回调,必须首先定义函数指针,请看下面的例子:
可以看出,函数的定义和函数指针的定义非常类似。一般为了简化函数指针类型的变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。
回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。同步回调:#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寄存器等)。将调用规范看成是函数类型的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。例如:
指针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)
#endif

using 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 something
while(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);  //非静态成员函数实现线程Wrapper
void 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_VER
HANDLE handle1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)funThreadAlgorithm,0,0,NULL);
CloseHandle(handle1);
#else
pthread_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_VER
HANDLE handle2 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)funThreadAlgorithm2,p,0,NULL);
CloseHandle(handle2);
#else
pthread_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);  //非静态成员函数实现线程Wrapper
void 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_VER
HANDLE handle2 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)funCallbackThread,p,0,NULL);
CloseHandle(handle2);
#else
pthread_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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  异步 回调