Linux学习笔记之callback

callback function

刚入职之时,小弟曾经受师兄指导写过一个回调,最近又回想到回调,思来想去,对回调的概念百思不得其解,困扰了好久。小弟愚钝,在查看了很多资料之后依然疑惑重重,犹如雾里看花终隔一层。如此两天,如骨在喉,实在是不吐不快。终于按奈不住心中躁动,拉起几位小伙伴深夜畅谈,终于拨开迷雾见明月。小弟谈谈自己的理解,希望对感兴趣的小伙帮能有所帮助;如果小弟有理解不妥的地方,更希望大家能帮忙指出,小弟万分感激。小弟在此拜谢了先~

  • callback function
  • example

callback function

官方解释

net 上有很多关于callback 的官方解释,小弟还是比较喜欢wiki上的解释。

In computer programming, a callback, also known as a “call-after” function, is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time. This execution may be immediate as in a synchronous callback, or it might happen at a later time as in an asynchronous callback. —— [ wiki]
这里写图片描述

这是wiki 上的原话,小弟就不献丑翻译了。

小弟的理解

下面是小弟的总结:

callback function 说白了其实就是: 一位管家提供了common的register interface 给callback 注册其function,等到caller在需要的时候调用这个interface。

如果你想知道这个管家 会是谁,其实这个时候可以说下,不要在意这些细节,但是小弟可以举例:如linux kernel/binder/server;如果你愿意,也可以是你自己创建的一个thread。 这里需要提到两个概念

  1. register interface;
  2. 函数指针;

register interface 当然最好是由管家提供,这样我们就不需要再用extern了。
当然callback function 的基础就是函数指针,所以我们得理解函数指针。当然关于函数指针,这个概念也是到处可以看到,为了让总结更加完善,小弟也就厚颜解释下了。

函数指针

先举出一个例子,pf就是函数指针,大家一看就明白了什么是函数指针。

int f(int);
int (*pf)(int) = &f;
int ans;
ans = f(25);
ans = (*pf)(25);
ans = pf(25);

example

callback 有synchronousasynchronous 两种情况。下面会针对这两种情况做一下举例。

synchronous

net上同步的列子不胜枚举,大部分情况下也都是以同步为例解释callback function。

#include <stdio.h>
#include <stdlib.h>

/* The calling function takes a single callback as a parameter. */
void PrintTwoNumbers(int (*numberSource)(void)) {
    int val1 = numberSource();
    int val2 = numberSource();
    printf("%d and %d\n", val1, val2);
}

/* A possible callback */
int overNineThousand(void) {
    return (rand()%1000) + 9001;
}

/* Another possible callback. */
int meaningOfLife(void) {
    return 42;
}

/* Here we call PrintTwoNumbers() with three different callbacks. */
int main(void) {
    PrintTwoNumbers(&rand);
    PrintTwoNumbers(&overNineThousand);
    PrintTwoNumbers(&meaningOfLife);
    return 0;
}

以上这段代码的执行结果如下:

1804289383 and 846930886
9778 and 9916
42 and 42

大家看到上面这段code 有何感想,可能会觉得这就是一个函数指针的应用而已,不过事实上,我就是这么认为。哈哈哈~ 小弟不才,只能看到这层,如果有哪位高手能看到更深的层次,还望不吝赐教,小弟感激不尽~

将上面这段代码稍作修改,就可以变成下面的样子:

#include <stdio.h>
#include <stdlib.h>

struct callfunc {
    void (*p1)(void);
    void (*p2)(void);
    void (*p3)(void);
};

/* A possible callback */
void currentRand(void) {
    printf("val is %d\n", rand()%100);
}

/* A possible callback. */
void overNineThousand(void) {
    printf("val is %d\n", (rand()%1000) + 9001);
}

/* A possible callback. */
void meaningOfLife(void) {
    printf("val is %d\n", 42);
}

/* register callback function */
void register_func(struct callfunc *func) {
    func->p1 = overNineThousand;
    func->p2 = meaningOfLife;
    func->p3 = currentRand;
}

/* Here we call three different callbacks. */
int main(void) {
    struct callfunc *f1 = (struct callfunc *)malloc(sizeof(callfunc));
    if (!f1) {
        return -1;
        printf("f1 is null\n");
    }
    register_func(f1);
    f1->p1();
    f1->p2();
    f1->p3();

    return 0;
}

执行结果如下:

val is 9384
val is 42
val is 86

很显然,这段code 与上一段并没有多大不同。但是仔细想想,如果有很多不同的module,都需要实现同一套功能,那么各自module 就可以分别调用注册函数,将自己的实体注册进来,这样caller就不需要为不同的module都写一套调用,caller 的函数就变的很简单,至于如何识别该用那一套,就不在callback 的考虑范畴之类了,当然如果大家感兴趣,可以给小弟留言。

asynchronous

说完了synchronous,接下来就该谈谈asynchronous。其实asynchronous是非常常见的,而且也是callback 应用的大部分场景。
仔细想想上一个code,这段code 其实在callback function注册的时候,并没有执行,而是等到某个时间点才开始执行,已经有一点异步的感觉了。
假设如果某一个callback function 被放到queue当中等待执行,caller 其实并没有等待callback function return 就直接返回了。这个就是比较明显的异步了。
异步的情况,kernel 里面可以说到处都可以看到,大家可以参考下kernel-4.4或者更新的版本,原生code 比较多,小弟就不再一一列举了。如果小伙伴比较感兴趣,可以留言给小弟,小弟会再想办法举例说明。

小结

希望此文对各位能有所帮助,如果小弟所述有不正确的地方,还请大家不吝赐教。如果有疑问的地方,也可以给小弟留言,小弟会知无不言言无不尽。
纸上得来终觉浅,绝知此事要躬行。与大家共勉。

目录

[TOC]来生成目录:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值