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

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

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

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




猜你喜欢

转载自blog.csdn.net/Hahaha_Val/article/details/79642678