回呼函式在日常開發中使用廣泛,什么是回呼函式,為什么要使用回呼函式,如何使用回呼函式,本文將結合一個例子說明,
什么是回呼函式?
回呼函式也是函式,通俗的來說回呼函式是由開發者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監聽非阻塞方式,作者水平有限,有錯誤歡迎指正,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/241434.html
標籤:其他
