回调函数介绍和使用方法以及使用例子

回调函数在日常开发中使用广泛,什么是回调函数,为什么要使用回调函数,如何使用回调函数,本文将结合一个例子说明。

       什么是回调函数?

       回调函数也是函数,通俗的来说回调函数是由开发者A定义,另个开发者B实现,并在A实现的函数中调用的函数。

      为什么使用回调函数?

      代码设置都是分层设计的,也就是模块化设计,特别是嵌入式的开发。代码的编码都是分工合作的,每个人负责不同的部分。而不同的层次之间也有相互依赖。假如模块A的数据如何传给另一个模块B,模块B如何处理数据,模块A是不关心的。这就需要模块B将自己的处理函数给模块A,这就是所谓的 函数注册。这个注册的函数是回调注册函数,被注册的函数就是回调函数。

     回调函数实现方式?

      回调函数实现方式就是将函数的指针作为注册函数的参数注册给调用者,调用者使用函数指针(一般为全局函数指针)接收该回调函数。这个过程一般是注册回调的过程。调用者在没有接收到这个回调函数之前,直接先使用全局指针完成函数调用,所以说代码运行之前,必须要完成函数的注册。不然找不到该函数,会导致空指针错误。

    例子:假如要完成温湿度采集和处理,如何实现?考虑到模块化设计和分工,甲完成温度的采集,乙完成湿度的采集,丙处理这个两个数据。丁负责写整个应用将三个部分串起来。其中甲乙的数据就可以使用回调函数传输给丙处理。开发之前需要甲乙需要定义各种头文件里面提供自己函数声明和回调函数的声明,以及回调函数的注册方法。

    甲:负责temperature 采集。

    乙:负责humidity采集。

    丙:负责数据处理。

    丁:负责应用程序的开发。

在linux环境下使用多线程的方式模拟,线程之前使用管道通信实现。

甲同学实现部分:

头文件

temperature_drive.h

#ifndef _DRIVE_TMP_H__
#define _DRIVE_TMP_H__
typedef int (*callback_fuction)(int a,char *data); //函数指针定义
int register_callback_func_tmp(callback_fuction callback);
void start_tem_drive(pthread_t *thread);
#endif

 

C文件

temperature_drive.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "temperature_drive.h"
pthread_mutex_t mutex;
callback_fuction g_callback;
//注册回调函数
int register_callback_func_tmp(callback_fuction callback)
{
    g_callback = callback;
}


void* callback_thread_tem(void *p1)
{
    while(1)
    {
        int static num = 0;
        if(NULL == g_callback)
        {
            printf("WAITE REGIST! \n");
            exit(0);
        }
         sleep(2);
         pthread_mutex_lock(&mutex);
         g_callback(num,"temperature");//调用回调函数将数据返回到回调函数的实现方,也就是丙
         num++;
         pthread_mutex_unlock(&mutex);
    }
}

void start_tem_drive(pthread_t *thread)
{
    //创建线程
    pthread_t pthread;

    pthread_create(&pthread,NULL,callback_thread_tem,NULL);
    
    *thread = pthread;

    //pthread_join(pthread,NULL);
    sleep(1);
}

 

乙同学实现部分

头文件

humidity_drive.h

#ifndef _HUMIDITY_H__
#define _HUMIDITY_H__
 
typedef int (*callback_fuction_hum)(char *data); //函数指针定义
int register_callback_func_hum(callback_fuction_hum callback);
void start_hum_drive(pthread_t *thread);
#endif

C文件

humidity_drive.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "humidity_drive.h"
extern pthread_mutex_t mutex;
callback_fuction_hum g_callback_humidity;
//注册回调函数
int register_callback_func_hum(callback_fuction_hum callback)
{
    g_callback_humidity = callback;
}


void* callback_thread_hum(void *p1)
{
    while(1)
    {
        if(NULL == g_callback_humidity)
        {
            printf("WAITE REGIST! \n");
            exit(0);
        }
         sleep(3);
         pthread_mutex_lock(&mutex);
         g_callback_humidity("humidity");//通过回调函数将数据返回
         pthread_mutex_unlock(&mutex);
    }
}

void start_hum_drive(pthread_t *thread)
{
    //创建线程
    pthread_t pthread;

    pthread_create(&pthread,NULL,callback_thread_hum,NULL);
    *thread = pthread;

    //pthread_join(pthread,NULL);
    sleep(1);
}

丙同学部分

头文件

data_handle.h

#ifndef _DATA_HANDLE_H__
#define _DATA_HANDLE_H__
void data_handle_init(void);
void start_data_handle(pthread_t *thread);
#endif

C文件

data_handle.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "data_handle.h"
#include "temperature_drive.h"
#include "humidity_drive.h"
//注册回调
int pip_ios_fd[2] ;
int handle_tem_data_callback(int num, char *data)  //实现具体温度处理的回调函数
{
    printf("handle_tem_data_callback\n");
    int wret = write(pip_ios_fd[1], data, sizeof(data));
    printf("num%d\n",num);
    return 0;
    

}
int handle_hum_data_callback(char *data) //实现具体的湿度处理的回调函数
{
    printf("handle_hum_data_callback\n");
    int wret = write(pip_ios_fd[1], data, sizeof(data));
}


void* data_handle_thread(void *p1)
{

    while(1)
    {
        char data[10];
        int ret = read(pip_ios_fd[0], data, sizeof(data));//管道为空阻塞
        printf("rev data len:%d,data is:%s\n",ret,data);//集中处理所有收到的数据
    
    }
}
void data_handle_init()
{
    
    register_callback_func_tmp(handle_tem_data_callback);//调用注册回调函数
    register_callback_func_hum(handle_hum_data_callback);
}
void start_data_handle(pthread_t *thread)
{
    //创建线程
    int pip_ret = pipe(pip_ios_fd);
    
    pthread_t pthread;

    pthread_create(&pthread,NULL,data_handle_thread,NULL);

    //pthread_join(pthread,NULL);
    *thread = pthread;
    sleep(1);
}

丁同学应用部分:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "temperature_drive.h"
#include "humidity_drive.h"
#include "data_handle.h"

int main()
{
    /*先调用初始化,为了先注册回调函数*/
    pthread_t thread,thread1,thread2;
    data_handle_init();
    /*启动温度检测*/
    start_tem_drive(&thread);
    /*启动湿度检测*/
    start_hum_drive(&thread1);
    /*启动数据处理*/
    start_data_handle(&thread2);
    pthread_join(thread,NULL);
    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    return 0;
}

写个简单的makefile

UGW_INC += -I $(pwd) ./
CC = gcc
UGW_SRCS = $(wildcard *.c)
UGW_OBJS = $(patsubst %.c,%.o, $(UGW_SRCS))

all: $(UGW_OBJS)
%.o:%.c
	$(CC) -c  -o $@ -MD $< $(UGW_INC)

clean:
	-rm -f *.o
	-rm -f *.d

一键make,运行。ok,搞定。demo虽小,五脏俱全。通过demo,可以了解,代码的分层设计,代码的分工,回调函数的使用,线程间通信方式(管道)。还有改进的空间,有时间优化丙管道阻塞读,改为select监听非阻塞方式。作者水平有限,有错误欢迎指正。

  • 10
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值