回调函数(Callback Functions)

回调函数是指一个通过函数指针调用的函数。回掉函数不是由该函数的实现方法直接调用,而是在特定时间或条件发生时由另一方调用的,用于对该事件或条件进行响应。

回调函数的简单实现

C和C++中,可以通过函数指针的方式实现回调函数。如下例:

#include <stdio.h>

typedef int (*callf)(int a);

/* 回调函数 */
int fa(int a) {
    printf("a is called, a is %d\n", a);
    return a;
}

/* 回调函数 */
int fb(int b) {
    printf("b is called, b is %d\n", b);
    return b;
}

int call1(callf pcf, int arg) { /* 通过typedef函数指针的方式 */
    printf("call1 is called, arg is %d\n", arg);
    pcf(arg); // 调用回调函数
    return arg;
}

int call2(int (*ptr)(int ), int arg) { /* 通过直接定义函数指针的方式 */
    printf("call2 is called, arg is %d\n", arg);
    ptr(arg); // 调用回调函数
    return arg;
}

int main(int argc, char *argv[])
{
    int arg = 10;
    call1(&fa, arg);
    call2(&fb, arg);
    return 0;
}

在上例中,我们可以看到,在C/C++中可以直接将函数指针作为参数传参,并通过函数指针进行函数调用和 传递参数,从而实现了回调函数。

回调函数与事件模型

首先声明时间模型、回调函数和事件注册函数。

// 事件模型声明
struct Event;
// 回调函数声明
typedef void (*pEvent_cbF)(const struct Event *e, void *extra_data);
// 事件注册函数声明
void event_cbF_register(Event *e, pEvent_cbF callback, void *data);

在事件调度器(event dispather)中,通常将回调函数放在结构体中。trigger函数供外部调用来触发 事件,当时间发生时,会调用回调函数。

struct Event {
    pEvent_cbF callback;
    void *data;
    void trigger() {
        printf("Event occur!\n");
        this->callback(this, nullptr);
    }
    void trigger(void *extra_data) {
        printf("Event occur with extra data: %s\n", (const char *)extra_data);
        this->callback(this, extra_data);
    }
};

接下来,实现事件注册函数和回掉函数。

void event_cbF_register(Event *e, pEvent_cbF callback, void *data) {
    e->callback = callback;
    e->data = data;
}

void my_event_cbF(const struct Event *e, void *extra_data) {
    printf("my event callback function is called.\n");
    printf("event data: %s\n", (const char *)(e->data));
    if (extra_data != nullptr) {
        printf("extra data: %s\n", (const char *)(extra_data));
    }
}

在 main 函数中创建事件,并通过 trigger 触发。测试:

int main(int argc, char *argv[])
{
    Event custom_event;
    char custom_data[50] = "Event message of custom_event.";
    event_cbF_register(&custom_event, &my_event_cbF, custom_data);
    custom_event.trigger();
    
    printf("\n");
    char extra_data[50] = "Extra data when trigger custom_event.";
    custom_event.trigger(extra_data);

    return 0;
}

运行上述程序,将获得如下输出:

    Event occur!
    my event callback function is called.
    event data: Event message of custom_event.

    Event occur with extra data: Extra data when trigger custom_event.
    my event callback function is called.
    event data: Event message of custom_event.
    extra data: Extra data when trigger custom_event.

回调函数与异步非阻塞

将回调函数放在单独的线程中执行,便可以做到异步非阻塞处理。