APUE在這方面似乎沒有給出範例,必須要到他另外一本著作去看
System V的IPC除了PIPE之外主要就是message queue, semaphore, shared memory,三者使用方式都很類似,主要是藉由identifier=>key=>id
identifier指的是一個可以產生唯一key的物件,書內有幾種使用方式,identifier大致上就是一個整數,或者由其他方式產生的整數
1. 直接寫在檔案內,所有include到的程式就可以使用到,但是有名稱衝突的問題
2. 藉由產生物件的程式指定,輸出到檔案,其他程式再去讀取
3. 寫在程式內,利用parent/child關係共享,但只能適用於fork()
4. 使用事先知道的整數跟一個路徑,再利用ftok()產生唯一的key
有了key_t key之後,用來產生物件,他會回傳物件的ID,之後就是使用ID來做操作了,大致上操作為,新增為xxxget(),修改屬性以及刪除則是xxxctl()
結論可以講在前面,作者認為除非必要,不然使用PIPE跟shared memory就可以了,message queue跟semaphore,一則效能沒有太優,又有其他問題semaphore則是沒有良好的控管,維護比較困難
接下open server框架,簡直是整本書最精華的部分了,看了好幾次才看懂他的意圖,如果不了解作者的意圖,可以參考figure 17.1,裡面牽涉到process控制、IPC、terminal,整本書大多數的技巧都用上了
2013年1月27日 星期日
2013年1月22日 星期二
select作為socket多工
select作為socket多工,這是基本上的精神,但是有兩點要注意
參考資料:
http://fanqiang.chinaunix.net/a4/b7/20010913/0900001283.html
http://www.tenouk.com/Module41.html
- listen()呼叫的時候,socket已經ready,accept()則是資料來到queue中,所以用select可以得知狀況大多在listen()之後accept()之前
- 呼叫select()之後並不表示accept()不會block process,在處理資料過程,如果使用到任何block IO,整個process還是會被block,所以有很多程式使用fork()
參考資料:
http://fanqiang.chinaunix.net/a4/b7/20010913/0900001283.html
http://www.tenouk.com/Module41.html
2013年1月21日 星期一
login & terminal
linux在/dev下面一堆terminal的devices,搞得有點頭昏眼花,因為過去老舊的電腦常常靠著COM port與主機相連,所以在multiple user的狀況下,就是如何與terminal/tty做溝通囉,直接看richard stevens的圖
流程大致如下
現在大家大多使用網路,以前開發者的想法蠻不錯的,就是只要做出pesudo的tty,讓程式以為自己在跟tty溝通,那麼過去的程式都不用動就可以移植過來,所以圖形就變得如下
rlogind也可能是inetd主要作為pty (pesudo tty)中間的媒介
這下子終於大概了解到/dev底下一堆tty以及pty在做啥用的了
流程大致如下
- 在開機的時候init會根據/etc底下的設定,init會fork出新的process並且exec tty(看有設定與有多少個COM port)
- 找到對應device,並且將0, 1, 2這些IO對應好,跟著顯示exec login這個程式,也就是提示user/password輸入,這些程式都具備有root身分
- 當對應完成的時候,將exec login_shell,可能是bash shell或者其他,使用setuid()...等等,將process權限設定為使用者的權限,shell會與terminal連結好,使用者就可以開始進行操作了
現在大家大多使用網路,以前開發者的想法蠻不錯的,就是只要做出pesudo的tty,讓程式以為自己在跟tty溝通,那麼過去的程式都不用動就可以移植過來,所以圖形就變得如下
rlogind也可能是inetd主要作為pty (pesudo tty)中間的媒介
這下子終於大概了解到/dev底下一堆tty以及pty在做啥用的了
signal的省思
剛開始接觸signal沒多久,就一頭栽入了那些signal與訊號之間的關係,然後開始對應process生命週期與signal之間的聯繫,完全忽略了signal的本質asynchronous!!
asynchronous是一個"可怕"的詞,他有著可怕的效能以及不可捉摸的特性,人們最近對效能的貪婪在node.js可見一班,然後又發現他很難使用同步的功能甚至於說次序(order),很難確定事件之間發生的次序。
signal由於是asynchronous也就是表示他隨時會發生,所以不能對process做任何的假設,如果把signal拿來做為異常處理的手段之一,恐怕只有exit跟longjmp(結果通常也是跟著接exit)是說的上安全的。比方說,當一個process在執行malloc到一半的時候,被signal中斷,跟著signal裡面不管是使用該記憶體或者重新配置該記憶體,這都會引發不可臆測的問題
當然也可以介入更多的努力,力保signal產生的時候,這時process因為某些條件來說,是可以假定他沒有問題的,不過這通常伴隨著效能低落的問題
話說回來,很多programmer對signal的處理方式是忽略,少數採用類似cpu對deadlock的手法,也就是假設signal可以正常的運作,不正常的狀況很少,這是一個trade off
其實這也是一個reentrant的問題,在IBM的文章有討論到,的確有點難解
http://www.ibm.com/developerworks/linux/library/l-reent/index.html
或許最單調的處理方式就如文章內提到的使用sigprocmask()去block所有signal,形成一個critical section來保護
所以signal對unix/linux是必要的,因為這是系統機制的一部份,可是在使用上卻是要小心謹慎的,signal本質上應該是類似一個notify,而不應該再signal handler上處理太多的動作。
P.S. 一個有趣的定義是#define SIG_IGN ((void (*)(int))1);事實上我們應該不可能有address為0x1的pointer,這是隸屬於kernel space的地方,所以猜測應該是在kernel某個部分藉由判斷signal pointer為0x1就把它忽略吧,有人說在do_signal()這個function內,可是我在翻閱kernel的signal.c裡面卻沒有這個判斷式
參考資料:
http://zh.wikipedia.org/wiki/%E5%8F%AF%E9%87%8D%E5%85%A5
asynchronous是一個"可怕"的詞,他有著可怕的效能以及不可捉摸的特性,人們最近對效能的貪婪在node.js可見一班,然後又發現他很難使用同步的功能甚至於說次序(order),很難確定事件之間發生的次序。
signal由於是asynchronous也就是表示他隨時會發生,所以不能對process做任何的假設,如果把signal拿來做為異常處理的手段之一,恐怕只有exit跟longjmp(結果通常也是跟著接exit)是說的上安全的。比方說,當一個process在執行malloc到一半的時候,被signal中斷,跟著signal裡面不管是使用該記憶體或者重新配置該記憶體,這都會引發不可臆測的問題
當然也可以介入更多的努力,力保signal產生的時候,這時process因為某些條件來說,是可以假定他沒有問題的,不過這通常伴隨著效能低落的問題
話說回來,很多programmer對signal的處理方式是忽略,少數採用類似cpu對deadlock的手法,也就是假設signal可以正常的運作,不正常的狀況很少,這是一個trade off
其實這也是一個reentrant的問題,在IBM的文章有討論到,的確有點難解
http://www.ibm.com/developerworks/linux/library/l-reent/index.html
或許最單調的處理方式就如文章內提到的使用sigprocmask()去block所有signal,形成一個critical section來保護
所以signal對unix/linux是必要的,因為這是系統機制的一部份,可是在使用上卻是要小心謹慎的,signal本質上應該是類似一個notify,而不應該再signal handler上處理太多的動作。
P.S. 一個有趣的定義是#define SIG_IGN ((void (*)(int))1);事實上我們應該不可能有address為0x1的pointer,這是隸屬於kernel space的地方,所以猜測應該是在kernel某個部分藉由判斷signal pointer為0x1就把它忽略吧,有人說在do_signal()這個function內,可是我在翻閱kernel的signal.c裡面卻沒有這個判斷式
參考資料:
http://zh.wikipedia.org/wiki/%E5%8F%AF%E9%87%8D%E5%85%A5
2013年1月20日 星期日
C++最佳化與inline跟一個小問題
inline的語意有時候有點模糊,其實主要因該是在最佳化的時候的解釋方式,compiler會試著將inline直接展開,也就是類似MACRO,好處是不會需要處理stack frame,這表示效能將會提升,同時大多數的書籍建議inline不宜過大,這樣才不會導致text區段太過肥大,聰明一點的compiler也會自行將肥大的inline變成function,所以這才導致了inline的語意有些模糊。同時,inline也可能因為展開的關係從symbol table移除,這樣一來在gdb不能使用b function_name,必須直接使用行號,這樣的小問題。
最佳化的技巧很多,有的compiler會將function的parameter直接放到register上面,這樣可以加速處理速度同時節省stack frame,當然會面臨到參數個數跟register個數的問題,其實有時候還會引發concurrency的問題,比方說,在平行處理的時候,最佳化有可能因為將變數對應到register,導致本來用來做critical section判斷的variable,但是兩個thread擁有不同的register,所以程式怎樣看都沒問題,但是執行起來就有問題,這樣的bug非常難以找到
最佳化的技巧很多,有的compiler會將function的parameter直接放到register上面,這樣可以加速處理速度同時節省stack frame,當然會面臨到參數個數跟register個數的問題,其實有時候還會引發concurrency的問題,比方說,在平行處理的時候,最佳化有可能因為將變數對應到register,導致本來用來做critical section判斷的variable,但是兩個thread擁有不同的register,所以程式怎樣看都沒問題,但是執行起來就有問題,這樣的bug非常難以找到
setjmp、longjmp以及C++ exception
之前略讀的一些linux driver以及linux kernel的書籍,對於底層稍微有一點點的了解,現在回頭過來看richard stevens的大作advanced programming the unix envrionment,真的又是別有一番風味阿~很多細節慢慢在心裡一一浮現
在其中提到了setjmp以及longjmp,為了克服goto不該使用,而且goto無法跳躍function call,其實主要原因應該是卡在stack frame的部分,在組合語言中,基本上程式可以跳到任意位置,但是stack frame是各家程式引入的機制,不遵循恐怕會有一些副作用,所以引入setjmp以及longjmp,此外書本中也提到了global variable以及register的狀態必須要注意,setjmp以及longjmp並無法回復他們的狀態,但其實還有更嚴重的是~~這個機制掠過了所有該free或者delete的空間@@a,這點書中就沒有提到了
跟著C++引入了exception,讓大家可以很歡樂的使用try~catch跟throw exception來處理這件事情又可以避開setjmp/longjmp的問題,C++是怎樣做到的,其實他偷偷在stack frame上面塞入了一個link list結構,每個list node又配置了一個exception handler,用來處理結束該stack frame之後該處理的事情
C++塞入了這些結構,表示programmer跟program在執行的時候必須要付出一些額外的代價,但是總比setjmp跟longjmp來的好
話說回來,不知道哪裡看來的一句話,一直縈繞在我的心頭:programmer不應該把例外處理當成程式流程的一部份。我一直無法參悟這句話,是說例外處理就是例外,不應該把例外處理當成程式流程中的一個處理過程?但是例為處理本身就程式的一環(?)難道寫成是不應該考慮例外嗎?還是例外就是意料之外,所以例外處理本身該做的就只有收拾善後跟列印錯誤??
在其中提到了setjmp以及longjmp,為了克服goto不該使用,而且goto無法跳躍function call,其實主要原因應該是卡在stack frame的部分,在組合語言中,基本上程式可以跳到任意位置,但是stack frame是各家程式引入的機制,不遵循恐怕會有一些副作用,所以引入setjmp以及longjmp,此外書本中也提到了global variable以及register的狀態必須要注意,setjmp以及longjmp並無法回復他們的狀態,但其實還有更嚴重的是~~這個機制掠過了所有該free或者delete的空間@@a,這點書中就沒有提到了
跟著C++引入了exception,讓大家可以很歡樂的使用try~catch跟throw exception來處理這件事情又可以避開setjmp/longjmp的問題,C++是怎樣做到的,其實他偷偷在stack frame上面塞入了一個link list結構,每個list node又配置了一個exception handler,用來處理結束該stack frame之後該處理的事情
C++塞入了這些結構,表示programmer跟program在執行的時候必須要付出一些額外的代價,但是總比setjmp跟longjmp來的好
話說回來,不知道哪裡看來的一句話,一直縈繞在我的心頭:programmer不應該把例外處理當成程式流程的一部份。我一直無法參悟這句話,是說例外處理就是例外,不應該把例外處理當成程式流程中的一個處理過程?但是例為處理本身就程式的一環(?)難道寫成是不應該考慮例外嗎?還是例外就是意料之外,所以例外處理本身該做的就只有收拾善後跟列印錯誤??
訂閱:
文章 (Atom)

