同步回調函數和異步回調函數


回調函數

回調函數一般是在封裝接口的時候,回調顯得特別重要,我們首先假設有兩個程序員在寫代碼,A程序員寫底層驅動接口,B程序員寫上層應用程序,然而此時底層驅動接口A有一個數據d需要傳輸給B,此時有兩種方式: 
1.A將數據d存儲好放在接口函數中,B自己想什么時候去讀就什么時候去讀,這就是我們經常使用的函數調用,此時主動權是B。 
2.A實現回調機制,當數據變化的時候才將通知B,你可以來讀取數據了,然后B在用戶層的回調函數中讀取速度d,完成OK。此時主動權是A。 
很明顯第一種方法太低效了,B根本就不知道什么時候該去調用接口函數讀取數據d。而第二種方式由於B的讀取數據操作是依賴A的,只有A叫B讀數據,那么B才能讀數據。也即是實現了中斷讀取。 
那么回調是怎么實現的呢,其實回調函數就是一個通過函數指針調用的函數。如果用戶層B把函數的指針(地址)作為參數傳遞給底層驅動A,當這個指針在A中被用為調用它所指向的函數時,我們就說這是回調函數。 
注意:是在A中被調用,這里看到盡管函數是在B中,但是B卻不是自己調用這個函數,而是將這個函數的函數指針通過A的接口函數傳自A中了,由A來操控執行,這就是回調的意義所在。 

同步回調和異步回調

首先,理解幾個概念:

1.回調可以是同步也可以是異步

2.同步可以是單線程也可以是多線程

   異步必須是多線程或多進程(每個進程可以是單線程) ==> 換句話說,異步必須依靠多線程或多進程才能完成

同步回調:把函數b傳遞給函數a。執行a的時候,回調了b,a要一直等到b執行完才能繼續執行;

異步回調:把函數b傳遞給函數a。執行a的時候,回調了b,然后a就繼續往后執行,b獨自執行。

直接看例子

A.h

#ifndef A_H
#define A_H

typedef void (*pcb)(int a); //函數指針定義,后面可以直接使用pcb,方便
void SetCallBackFun(int a, pcb callback);

#endif

同步回調

synA.c

#include <stdio.h>
#include "A.h"
 
//-----------------------底層實現A-----------------------------
//留給應用層B的接口函數
void SetCallBackFun(int a, pcb callback)
{
  printf("A:start\n");
  callback(a);
  printf("A:end\n");
}

synB.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "A.h"
//-----------------------應用者B-------------------------------
 
void fCallBack(int a) // 應用者增加的函數,此函數會在A中被執行
{
  //do something
  printf("B:start\n");
  printf("a = %d\n",a);
  sleep(5);
  printf("B:end\n");
}
 
int main(void)
{
  SetCallBackFun(4,fCallBack);
  return 0;
}

異步回調

asynA.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "A.h"
//-----------------------底層實現A-----------------------------
typedef struct parameter{
  int a ;
  pcb callback;
}parameter;
 
void* callback_thread(void *p1)//此處用的是一個線程
{
  //do something
  parameter* p = (parameter*)p1 ;
  sleep(5);
  p->callback(p->a);//函數指針執行函數,這個函數來自於應用層B
}
 
//留給應用層B的接口函數
void SetCallBackFun(int a, pcb callback)
{
  printf("A:start\n");
  parameter *p = malloc(sizeof(parameter)) ;
  p->a = a;
  p->callback = callback;
 
  //創建線程
  pthread_t pid;
  pthread_create(&pid,NULL,callback_thread,(void *) p);
  printf("A:end\n");
 
  //阻塞,等待線程pid結束,才往下走
  pthread_join(pid,NULL);
}

asynB.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "A.h"
//-----------------------應用者B-------------------------------
void fCallBack(int a) // 應用者增加的函數,此函數會在A中被執行
{
  //do something
  printf("B:start\n");
  printf("a = %d\n",a);
  sleep(5);
  printf("B:end\n");
}
 
int main(void)
{
  SetCallBackFun(4,fCallBack);
  return 0;
}

運行結果比較:

同步回調 異步回調
A:start
B:start
a = 4
B:end
A:end
A:start
A:end
B:start
a = 4
B:end

由執行結果可以看出:同步回調,A需要等待B執行完成才能執行A剩余的操作;異步回調,A剛執行B,不必等待B結束,就執行A剩余的操作,之后B的操作也隨之end。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM