最近開始要k一點系統程式,面試的時候都避免不了被問到有關系統程式的題目QQ
在看系統程式之前,目前覺得有個很重要的觀念一直沒有去弄懂,那就是callback function到底是什麼?從網路搜尋中找到了一個很好的解釋!
Callback = Call back = Call me back when you have done the job = 回電﹝回個電話﹞ = 做好了請叫我一下
這句話完全道盡一切callback function的精神,其實callback精神很常會出現在multi-thread的scenario,例如常常在寫iOS的app,裡面經常會遇到需要async的向server請求資料,當button按下去的時候,app就會啟動一個thread去向server請求資料,而我們可以繼續做想做的事情,當獲得server的資料後,代表"工作完成",然後用delegate的方式去通知目前的main thread!在iOS常用的delegate來達到callback的目的,既然如此,就來看看非物件導向要怎麼辦到callback!
function pointer:
在網路上查了一下宣告function pointer的方式如下: (*指標變數名)(參數)
在這裡需要很清楚的分辨"*"是放在括號內還是直接接function
int *function_1(int a); //指標函數 int (*function_2)(int a); //函數指標
上面的註解還蠻繞口的,function_1為指標函數,就是"回傳"的值為一個"指標",而function_2為函數指標,代表"指向函數"的指標,差別在一個是回傳指標,一個是本身就是指標,反正指標就是用來指向記憶體的位置,所以function pointer一樣不例外,他是指向function記憶體的位置,因為function在程式執行的時候會被放在某個記憶區塊,function pointer就是用來"動態"指向開記憶區塊然後使用該function。
example:
#include <stdio.h> void printKer(void){ printf("Hello Ker\n"); } void printTwoInputNum(int a, int b){ printf("Hello (%d, %d)\n",a,b); } int main(int argc, char** argv){ int a = 10; int b = 20; void (*funKerPtr)(); void (*funPrintTwoInputNum)(int a,int b); funKerPtr = printKer; funPrintTwoInputNum = printTwoInputNum; (*funKerPtr)(); (*funPrintTwoInputNum)(a,b); return 0; }
上面的example實在是有點智障,直接call function不就好了,幹嘛用function pointer,這個example把function pointer用的很爛,雖然function pointer可以這樣用,但有種殺雞焉用牛刀的感覺,什麼時候非用function pointer不可?那就是callback的時候了,下面example是系統程式會看到的一個signal example
example:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/time.h> void signalHandle(int signal){ switch(signal){ case SIGHUP: printf("Catch Signal: SIGHUP(%d)\n",signal); break; case SIGINT: printf("Catch Signal: SIGINT(%d)\n",signal); break; case SIGQUIT: printf("Catch Signal: SIGQUIT(%d)\n",signal); break; case SIGALRM: printf("Catch Signal: SIGALRM(%d)\n",signal); break; default: printf("Unknown Signal:%d\n",signal); break; } } int main(int argc, char **argv){ int secDelay = 5; printf("current process ID = %d\n",(int)getpid()); signal(SIGINT,signalHandle); signal(SIGQUIT,signalHandle); signal(SIGALRM,signalHandle); alarm(secDelay); while(1) pause(); return 0; }
signal在系統程式常常拿來做process之間的通信,在上面的example只是一個接收ctrl+/ or ctrl+c或等五秒會跑出一個signal的example,可以看到我們call signal後,unix like的系統會在背景偵測接收到的signal,而signal()函數把signalHandle函數當成input?其實第二個參數是一個function pointer,代表指向signalHandle的一個pointer,所以才可以這樣寫,signal函數在call完之後會在背景async的方式執行,他的工作就是偵測"signal",所以當它偵測到signal的時候(工作做完),這時要告訴我們(callback)的main function他做完惹,這時的做法就是要透過一個function來通知,而這個function為一個callback的功用,因此signalHandle為signal的一個callback function。
可以看到我們可以對callback function做一些客製化的動作,例如更改print出來的句子之類的,所以callback的另外一個好處就是我們可以在某function工作完之後做一些客製化的動作,而不需要去了解到底該function怎麼工作的。
後記: 之前上計程的時候老師沒有強調function pointer和callback概念的重要,老師只說這不會考!結果最近才知道這個概念超重要,整個callback都建立在這個觀念上。現在流行很多的framework都會用到此概念,為什麼這個概念重要,個人認為framework與傳統的library有點不一樣的地方在library都是一堆function,當需要哪些function的時候,直接call他就可以,而framework則不是,它是"一套"規則,framework最常幹的事情就是把實作給"包"起來不讓你看,但是怎麼把執行後的結果傳出來給我們看,或者我們叫這個framework做事怎麼知道他做完沒?因此framework常常會用delegate(物件導向)或是callback的方式來通知我們或是讓我們有最低限度的自定項,老實說我覺得framework都有他的精神所在,本質上framework是希望幫程式設計師解決掉一些麻煩的事,例如access database時免去下sql語法之類的,讓程式設計師可以專注在開發上,但是設計到好用的哲學與概念通常不是那麼簡單,需要花心思去學,好的framework在學完之後會發現真的省了很多事,而這些好用的framework通常都會搭配callback的概念。
reference:
沒有留言:
張貼留言