文章目录

  • 函数回调:
  • 代码示例
  • 回调函数构造
  • 总结
  • 第一步 声明
  • 第二步 构造调用关系
  • 第三步 建立回调
  • 第四步 调用回调
  • 第五步 传入回调


函数回调:

函数回调就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应

代码示例

int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...)

这个是我在写redis异步调用时的函数。
ac:一个参数,用来存储跟连接相关的参数,客户端服务端均有。
fn:一个回调函数,当执行format的命令后,会自动调用 fn函数
privdata:一个自己的数据,可以自行定义

我的需求:现在已有的机制,保证接收到format命令的回复的时候,自行调用fn。这时我需要通知外部进程,这边状态的变化,所以需要callbackfn fn里面再写一个函数,通知外部变化。但是外部的变化响应,需要结合外部的包来实现,所以我需要外部定义如何去通知到外部变化。

所以现在,就是想办法,让privdata变成一个函数,当接收到命令回复调用fn函数时,fn函数内部执行privdata(让void *privdata变成一个函数),通知外部进程,保证了可以根据不同的命令,有不同的通知。

回调函数构造

data是外部传入的函数指针,是void * 类型
我们需要订阅某个频道,但是订阅后,不是立马获取到结果;需要有人在channel的频道里面发布消息后,我们才能收到消息,所以整个消息指令的订阅和收到回复(收到订阅消息)是异步进行。

int retStatus;
if(NULL==data)
{
    retStatus=redisAsyncCommand(rac,commandCallBack,NULL,"SUBSCRIBE %s",channel);
}
else
    retStatus=redisAsyncCommand(rac,commandCallBack,data,"SUBSCRIBE %s",channel);

接收到channel频道的消息后,会调用commandCallBack函数
reply就是redisReply *类型的回复,存储了服务端的回复消息。
void *notify就是我们在redisAsyncCommand的void *privdata,是我们自己传入的参数

void commandCallBack(redisAsyncContext * redis_context,void *reply,void * notify)
{
    if(NULL==reply || NULL==redis_context)
    {
        return ;
    }
    redisReply *r=(redisReply *)reply;
    printToScreen(r);
    if (r->type == REDIS_REPLY_ARRAY &&r->elements == 3)
    {
        printf("Recieve message: %s : %d : %s : %d : %s : %d \n",r->element[0]->str, r->element[0]->len,
        r->element[1]->str, r->element[1]->len, r->element[2]->str, r->element[2]->len);
    }
    //todo notify outside
    notifyM(notify,r);
}

这时我们调用了 notifyM
notifyM我们构造了一个中间的模板,相当于根据接收到的函数指针,都会让函数指针将第二个参数,进行下一步的调用。

void notifyM(void (*NotifyMessageFn) (redisReply *) ,redisReply * r)
{
    (*NotifyMessageFn)(r);
}

这样其实就完成了整个回调函数过程的构造。

总结

根据void *类型的参数构造一个属于我们自己的函数

第一步 声明

typedef void (*NotifyMessageFn) (redisReply *);

第二步 构造调用关系

相当于一个中间步骤,不同的回调函数,可以都调用这个模板

void notifyM(void (*NotifyMessageFn) (redisReply *) ,redisReply * r)
{
    (*NotifyMessageFn)(r);
}

第三步 建立回调

已有 void * notify,是我们传入的函数
函数内可以知道我们需要的参数 redisReply * r

根据模板notifyM,创建具体的回调函数,传入对应类型

void updateInfo(redisReply * r)
{
    printf("yr\n");
    printToScreen(r);
}

第四步 调用回调

这时的回调

int subscribeChannelMessage(redisAsyncContext *rac,char * channel,void * data)
{
......
	notifyM(notify,r);
}

第五步 传入回调

updateInfo就是我们的回调,传入一个void *类型的回调,完成整个回调函数的构造

subscribeChannelMessage(r->rac,"+switch-master",updateInfo);