Linux進程間通信通常用到的方法有:匿名管道、命名管道、信號、消息隊列、共享內(nèi)存、信號量和套接字,其中匿名管道只用于有親屬關系的父子進程之間的一種單功通信方式,在fork()創(chuàng)建進程之前創(chuàng)建匿名管道。其中個人用的最多的是命名管道、共享內(nèi)存和信號量:命名管道由于返回的文件描述符,可以十分方便的融合到現(xiàn)有的select/poll/epoll框架下面去;信號量主要用于模擬進程間互斥的行為;共享內(nèi)存用于進程間大規(guī)模的數(shù)據(jù)共享。陳碩的一句名言就是“在多進程之間共享內(nèi)存無異于掩耳盜鈴”,其實多進程間通過共享內(nèi)存的方式共享數(shù)據(jù)弊端和限制確實很多:首先共享內(nèi)存中不能共享指針,而指向共享內(nèi)存段本身的指針也最好用便宜的方式退化指針;如果共享內(nèi)存的數(shù)據(jù)經(jīng)常會被修改,那更是個災難。當然簡單只讀數(shù)據(jù)是可以的,比如Nginx的緩存也使用了共享內(nèi)存。
多進程程序的好處,就是消除了進程之間的耦合度后,操作系統(tǒng)的保護機制可以讓多個進程更加的獨立可靠,而且分成多個進程之后管理進程比管理線程方便靈活的多;同時,多進程程序可以實現(xiàn)進程的特異化管理,比如在Nginx設計中master process是特權進程,可以讀取配置文件、修改數(shù)重要數(shù)據(jù)等關鍵操作,而worker process是普通權限進程,只負責業(yè)務方面的處理,符合系統(tǒng)管理中的最小化權限原則;再有就是多進程程序可以進行業(yè)務的熱更新平滑升級,下面的Nginx算是將這一功能使用的淋漓盡致啊。
但是多進程的程序也有個問題,就是很多共享的資源、同步的手段都是命名全局的,很有可能進程意外退出后這些資源都得不到回收,補救的辦法只能是重啟操作系統(tǒng),汗~
1.3 多線程程序和信號
感覺信號一直是Linux平臺下開發(fā)比較頭疼的問題,尤其對于多線程情況下的程序,信號的處理將更加的復雜。
1.3.1 單線程程序中信號的處理方式
Linux中的信號的處理方式可以是SIG_IGN、SIG_DFL以及自己通過sigaction設置自定義處理函數(shù),進程創(chuàng)建的時候信號都有默認的處理方式,而用戶可以后續(xù)選擇忽略、默認處理方式、自定義處理這些信號(SIGKILL、SIGSTOP兩個信號只能默認處理方式,不能被忽略或者重定義處理),當進程接收到信號的時候就會轉(zhuǎn)向信號處理歷程去執(zhí)行。
信號可以在某些情況下被系統(tǒng)發(fā)送(比如觸發(fā)段錯誤),或者被別的進程使用kill發(fā)送,或者進程自己調(diào)用kill、raise系統(tǒng)調(diào)用觸發(fā)信號。進程可以通過signal mask去block某些信號,默認情況下是沒有信號被block的,此時如果被block的信號發(fā)送過來了,將會被設置為pending的,然后一旦該進程unblock了該信號,pending的信號將會立即被傳遞。
1.3.2 pthreads庫多線程環(huán)境對信號處理的方式
pthreads庫多線程中信號處理的方式,和信號的種類、各個線程對信號的mask狀態(tài)共同決定的。
Linux中多線程環(huán)境下信號的種類可以分為同步(Synchronously)信號和異步(Asynchronously)信號:同步信號是針對某個線程的,比如某個線程執(zhí)行過程中除以零(SIGFPE)、訪問非法地址(SIGSEGV)、使用了broken的管道(SIGPIPE),這些信號都根某個特定的線程特定的執(zhí)行上下文有關,還有就是同個進程中線程之間通過pthread_kill顯式發(fā)送信號的情況;異步信號主要是其他進程向該進程通過kill向這個進程(而非其中的線程)發(fā)送信號,并不跟某個特定的線程相關聯(lián)的情況。
pthreads庫中多線程之間共享sigaction結構但是不共享sig_mask結構,這意味所有的線程共享相同的信號處理方式,而不論信號處理方式是誰設置的。進程在最初fork()后創(chuàng)建的第一個線程繼承了其signal mask,而通過pthread_create創(chuàng)建的其他線程也繼承了這個信號mask,后續(xù)可以通過pthread_sigmask接口控制本線程對某些信號的block或者unblock。
有了上面的知識,信號在多線程下的行為就可以被確定了:
(1). 所有的線程共享相同的sigaction,所以所有進程對某個信號的處理方式是完全相同的;
(2). 同步信號是針對某個特定線程的,該線程是否接收處理這個信號看其signal mask設置情況;
(3). 異步信號是針對這個進程的,當這種信號到達的時候,進程會從沒有block這個信號的線程集合中隨機選出一個出來處理這個信號,如果所有的線程都block該信號,那么這個信號將被pending起來,直到有線程unblock這個信號,就將其發(fā)送給那個線程處理;