文章目录
- 函数回调:
- 代码示例
- 回调函数构造
- 总结
- 第一步 声明
- 第二步 构造调用关系
- 第三步 建立回调
- 第四步 调用回调
- 第五步 传入回调
函数回调:
函数回调就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应
代码示例
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);