代码改变世界

回调函数

2014-05-15 10:56  NicGanon  阅读(511)  评论(0编辑  收藏  举报

使用回调函数实际上就是在调用某个中间层函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。

 

举个生活中的例子:你到一个商店买条烟,刚好你要的那种烟没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。

再举个编程方面的例子:比如一个网络服务端程序,可以注册一个连接回调函数,来处理来请求连接的客户端;一个消息回调函数来处理客户端发来的消息。这样主程序就不需要阻塞等待连接或者通信,在有连接来的时候由你使用的网络库或者系统自动调用你的处理连接的回调函数。需要注意的是,平时这个连接回调函数是不工作的,也不能由你的主程序显式的直接调用,只能在来连接的时候有库或者系统调用。消息处理回调函数同理。

 

回调函数通常与原始调用者处于相同的抽象层,不能是其成员函数之类的,下图是抽象层级示意图,来自维基百科。

 

回调函数就好像是一个中断处理函数,系统在符合你设定的条件时自动调用。为此,你需要做三件事:

1.       声明;

2.       定义;

3.       设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用。

 

下面是维基百科上的一个例子:

 1 #include <stdio.h>
 2 #include <signal.h>
 3 #include <unistd.h>
 4  
 5 void sig(int signum)
 6 {
 7         printf("Received signal number %d!\n", signum);
 8 }
 9  
10 int main(int argc, char *argv[])
11 {
12         signal(SIGUSR1, sig);
13  
14         pause();
15  
16         return 0;
17 }

 

还有一个多线程的例子,在创建线程的时候,会由pthread_create来调用回调函数,该回调函数打印出每个线程的tid

 1 #include <pthread.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #define NUM_THREADS    5
 5 
 6 void *PrintHello(void *threadid)//回调函数
 7 {
 8     long *tid;
 9     tid = (long*)threadid;
10     printf("Hello World! It's me, thread #%ld!\n", *tid);
11     pthread_exit(NULL);
12 }
13 
14 int main(int argc, char *argv[])
15 {
16     pthread_t threads[NUM_THREADS];
17     int rc;
18     long t;
19     for(t=0;t<NUM_THREADS;t++){
20         printf("In main: creating thread %ld\n", t);
21         rc = pthread_create(&threads[t], NULL, PrintHello, (void *)&t);
22         if (rc){
23             printf("ERROR; return code from pthread_create() is %d\n", rc);
24             exit(-1);
25         }
26     }
27 
28     /* Last thing that main() should do */
29     pthread_exit(NULL);
30 }