C語言 非同步回撥

夏菠發表於2015-08-26

本文主要講解如果實現回撥,特別是在封裝介面的時候,回撥顯得特別重要,我們首先假設有兩個程式設計師在寫程式碼,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來操控執行,這就是回撥的意義所在。
下面就通過一個例子來演示
首先寫A程式設計師的程式碼

//-----------------------底層實現A-----------------------------
typedef void (*pcb)(int a); //函式指標定義,後面可以直接使用pcb,方便
typedef struct parameter{
    int a ;
    pcb callback;
}parameter; 

void* callback_thread(void *p1)//此處用的是一個執行緒
{
    //do something
    parameter* p = (parameter*)p1 ;
    while(1)
    {
        printf("GetCallBack print! \n");
        sleep(3);//延時3秒執行callback函式
        p->callback(p->a);//函式指標執行函式,這個函式來自於應用層B
    }
}

//留給應用層B的介面函式
extern SetCallBackFun(int a, pcb callback)
{
    printf("SetCallBackFun print! \n");
    parameter *p = malloc(sizeof(parameter)) ; 
    p->a  = 10;
    p->callback = callback;

    //建立執行緒
    pthread_t thing1;
    pthread_create(&thing1,NULL,callback_thread,(void *) p);
    pthread_join(thing1,NULL);
}

上面的程式碼就是底層介面程式設計師A寫的全部程式碼,留出介面函式SetCallBackFun即可

下面再實現應用者B的程式,B負責呼叫SetCallBackFun函式,以及增加一個函式,並將吃函式的函式指標通過SetCallBackFun(int a, pcb callback)的第二個引數pcb callback 傳遞下去。

//-----------------------應用者B-------------------------------
void fCallBack(int a)       // 應用者增加的函式,此函式會在A中被執行
{
    //do something
    printf("a = %d\n",a);
    printf("fCallBack print! \n");
}


int main(void)
{
    SetCallBackFun(4,fCallBack);

    return 0;
}

執行程式會看到

先會列印A程式的                 printf("GetCallBack print! \n");
然後等待3秒鐘才會列印應用者B的    printf("fCallBack print! \n");

相關文章