您的位置:首页 > 运维架构 > Linux

C高级——回调函数

2017-03-03 00:00 120 查看

回调的实质:

其实回调就是一种利用函数指针进行函数调用的过程。 函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数

回调的基本使用思想是,如果你有一个对数的操作,你现在还不知道是对它做加还是乘,还是别的什么运算。这个时候就可以定一个标准的函数框架,在调用的时候,将我要用的那个函数名作为参数传入,则进行相应的操作。

回调的实现:

/*
*	这是一个简单的回调函数示例
*	当我想预留操作接口的时候,通过typedef定义回调函数
*/

#include <stdio.h>

typedef int (* operation)(int i,int j);      //通过typedef定义回调函数

int plus(int i,int j){
printf("%s: ",__FUNCTION__ );
return i + j;
}
int minus(int i,int j){
printf("%s: ",__FUNCTION__ );        //__FUNCTION__为函数宏,此句会输出本函数名
return i - j;
}

int opr_cb(int i,int j,operation cb){
return cb(i,j);
}
int main(){
operation cb = plus;              //利用回调函数名创建回调函数,并赋值
printf("%d\n",opr_cb(3,5,cb));    //调用回调函数,cb为函数名;也可以直接使用plus或minus作为参数传递
return 0;
}

/*
*	输出结果:
*		当cb赋值为plus时,输出:"plus: 8";
*		当cb赋值为minus时,输出:"minus: -2";
*/


回掉的应用:

1、消息、事件处理。事件程序监测事件,同时维护一个回调函数列表,当有事件发生的时候发给所有注册的函数。直接实现是同步调用的,注册回掉是一种异步调用的关系。

2、预留接口。在模块设计的时候,知道要对数据做操作,但又不知道具体是什么操作,提供一个callback的接口,由用户实现具体的操作。

/*
*	这是一个简单的事件推送示例
* 	事件检测程序负责检测是否有事件发生
* 	主程序维护一个事件的回掉注册表,当有事件发生的时候,将消息发送给所有注册的回掉程序
*/
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "string.h"
#include "pthread.h"
#include "sys/time.h"

enum Boolean{
false = 0,
true = (!false)
};

typedef enum		//事件类型,可以根据自己的需要而添加
{
T_NOTICE = 0,
T_TIME = 1
}event_type;

typedef struct 		//事件消息定义
{
event_type type;
union{
char txt[200];
time_t time;
}content;		//两类消息,对应的有自己的数据类型
}event_msg;
event_msg g_msg;
volatile static event_flag = false;

typedef void (*event_cb)(event_msg *msg);	//回调申明
unsigned int event_num = 0;		//MAX值此处未定义
typedef struct event_factory	//回调函数的注册
{
event_cb cb;
struct event_factory *next;
}EVENT_FACTORY;
EVENT_FACTORY event_head;

int event_factory_init()       //初始化注册表头
{
memset(&event_head,0,sizeof(event_head));
event_head.cb = NULL;
event_head.next = NULL;
return true;
}

int event_factory_insert(event_cb cb)  //注册表注册函数
{
if(cb == NULL)
return false;

EVENT_FACTORY *new = NULL,*tmp = NULL;

if(event_num == 0)
{
event_head.cb = cb;
}
else
{
new = malloc(sizeof(EVENT_FACTORY));
memset(new,0,sizeof(EVENT_FACTORY));
new->cb = cb;
new->next = NULL;
tmp = &event_head;
while(tmp->next != NULL)
tmp = tmp->next;
tmp->next = new;
}
event_num++;

return true;
}
int event_factory_delete(void)         //注册表回收函数
{
EVENT_FACTORY *tmp,*now=&event_head;
while(now->next != NULL)
{
tmp = now;
now = now->next;
free(tmp);
}
return true;
}

static void UI_process(event_msg *msg)		//模拟UI处理线程
{
switch(msg->type)
{
case T_NOTICE:
printf("%s, %s\n", __FUNCTION__, (char *) &msg->content);
break;
case T_TIME:
printf("%s, Display %d\n", __FUNCTION__, *(int*)&msg->content.time);
break;
default:
printf("%s, event_type error\n", __FUNCTION__);
break;
}
}

static void Music_process(event_msg *msg)	//模拟音乐播放器处理线程
{
switch(msg->type)
{
case T_NOTICE:
printf("%s, %s\n",__FUNCTION__, (char *) &msg->content);
break;
case T_TIME:
printf("%s, jump\n",__FUNCTION__);
break;
default:
printf("%s, event_type error\n", __FUNCTION__);
break;
}
}

static void* event_process(void* data)		//模拟事件响应,不同进程使用消息队列来发送消息
{
struct timeval tv;
struct timezone tz;
while(1){
while(event_flag == true) sleep(0.2);
printf("check get T_NOTICE\n");			//while(get_notice());
memset(&g_msg, 0, sizeof(g_msg));
g_msg.type = T_NOTICE;
strncpy(g_msg.content.txt,"test",sizeof(g_msg.content.txt));
event_flag = true;
sleep(2);

while(event_flag == true) sleep(0.2);
printf("check get T_TIME\n");			//while(get_time());
memset(&g_msg, 0, sizeof(g_msg));
g_msg.type = T_TIME;
gettimeofday(&tv, &tz);
g_msg.content.time = tv.tv_sec;
event_flag = true;
sleep(2);
}
pthread_exit(0);
}

int main()
{
int i = 0;
pthread_t event_thread;
EVENT_FACTORY *tmp = NULL;
event_factory_init();
event_factory_insert(UI_process);
event_factory_insert(Music_process);

if(0 != pthread_create(&event_thread, NULL, event_process, NULL))
{
perror("event_thread create");
}

while(1)
{
while(event_flag == false) sleep(0.2);
tmp = &event_head;
for(i = 0; i < event_num ; i++)
{
if(tmp->cb == NULL) continue;
tmp->cb(&g_msg);
tmp = tmp->next;
}
event_flag = false;
printf("------------\n");
}
if(0 !=pthread_join(event_thread,NULL))
perror("pthread_join");
event_factory_delete();
return 0;
}

输出:

check get T_NOTICE
UI_process, test
Music_process, test
------------
check get T_TIME
UI_process, Display 1504685499
Music_process, jump
------------
check get T_NOTICE
UI_process, test
Music_process, test
------------
check get T_TIME
UI_process, Display 1504685503
Music_process, jump
------------

。。。。


总结:

除了这里列举的应用场景外,回调的使用场景还有很多,但都是对其本质的应用。所以理解了回调的本质,万变不离其宗。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息