linux環(huán)境進程間通信全_第1頁
linux環(huán)境進程間通信全_第2頁
linux環(huán)境進程間通信全_第3頁
linux環(huán)境進程間通信全_第4頁
linux環(huán)境進程間通信全_第5頁
已閱讀5頁,還剩14頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、LINUX 環(huán)境進程間通信(全)目錄一.Linux 環(huán)境進程間通信(一):管道及有名管道 31、 管道概述及相關 API 應用 31.1 管道相關的關鍵概念 31.2 管道的創(chuàng)建:31.3 管道的讀寫規(guī)則:31.4 管道應用實例:81.5 管道的局限性 102、 有名管道概述及相關 API 應用 102.1 有名管道相關的關鍵概念 102.2 有名管道的創(chuàng)建 102.3 有名管道的打開規(guī)則 102.4 有名管道的讀寫規(guī)則 112.5 有名管道應用實例 14小結:143、 Linux 環(huán)境進程間通信(二):信號(上)171、信號及信號來源 173.1 信號本質 173.2 信號來源 172、信號

2、的種類 173.3 可靠信號與不可靠信號 173.4 實時信號與非實時信號 183、進程對信號的響應 184、信號的發(fā)送 195、信號的安裝(設置信號關聯(lián)動作)206、信號集及信號集操作函數(shù):237、信號阻塞與信號未決 244、 Linux 環(huán)境進程間通信(二):信號(下)261、信號生命周期 262、信號編程注意事項 27%) 防止不該丟失的信號丟失 27%) 程序的可移植性 272.3 程序的穩(wěn)定性 283、深入淺出:信號應用實例 29實例一:信號發(fā)送及處理 29實例二:信號傳遞附加信息 30實例三:信號阻塞及信號集操作 32結束語:33四.Linux 環(huán)境進程間通信(三):消息隊列 34

3、1、消息隊列基本概念 342、操作消息隊列 35消息隊列 API363、消息隊列的限制 384、消息隊列應用實例 39小結:41五.Linux 環(huán)境進程間通信(四):信號燈 441、信號燈概述 442、Linux 信號燈 443、信號燈與內核 444、操作信號燈 455、信號燈的限制 476、競爭問題 487、信號燈應用實例 48六.Linux 環(huán)境進程間通信(五):共享內存(上)531、內核怎樣保證各個進程尋址到同一個共享內存區(qū)域的內存頁面 532、mmap()及其相關系統(tǒng)調用 5446)mmap()系統(tǒng)調用形式 5446)系統(tǒng)調用 mmap()用于共享內存的兩種方式 5446)系統(tǒng)調用 m

4、unmap()5546)系統(tǒng)調用 msync()553、mmap()范例 55范例 1:兩個進程通過映射普通文件實現(xiàn)共享內存通信 55范例 2:父子進程通過匿名映射實現(xiàn)共享內存 584、對 mmap()返回地址的訪問 59結論 61七.Linux 環(huán)境進程間通信(五):共享內存(下)611、系統(tǒng) V 共享內存原理 612、系統(tǒng) V 共享內存 API623、系統(tǒng) V 共享內存限制 634、系統(tǒng) V 共享內存范例 63結論 65Linux環(huán)境進程間通信(一):管道及有名管道1、管道概述及相關 API 應用管道相關的關鍵概念管道是 Linux 支持的最初 UnixIPC 形式之一,具有以下特點:管道

5、是半雙工的,數(shù)據(jù)只能向一個方向流動;需要雙方通信時,需要建立起兩個管道;只能用于父子進程或者兄弟進程之間(具有親緣關系的進程);單獨構成一種獨立的文件系統(tǒng):管道對于管道兩端的進程而言,就是一個文件,但它不是普通的文件,它不屬于某種文件系統(tǒng),而是自立門戶,單獨構成一種文件系統(tǒng),并且只存在與內存中。數(shù)據(jù)的讀出和寫入:一個進程向管道中寫的內容被管道另一端的進程讀出。寫入的內容每次都添加在管道緩沖區(qū)的末尾,并且每次都是從緩沖區(qū)的頭部讀出數(shù)據(jù)。管道的創(chuàng)建:#includeintpipe(intfd2)該函數(shù)創(chuàng)建的管道的兩端處于一個進程中間,在實際應用中沒有太大意義,因此,一個進程在由 pipe()創(chuàng)建管

6、道后,一般再 fork 一個子進程,然后通過管道實現(xiàn)父子進程間的通信(因此也不難推出,只要兩個進程中存在親緣關系,這里的親緣關系指的是具有共同的祖先,都可以采用管道方式來進行通信)。管道的讀寫規(guī)則:管道兩端可分別用描述字 fd0以及 fd1來描述,需要注意的是,管道的兩端是固定了任務的。即一端只能用于讀,由描述字 fd0表示,稱其為管道讀端;另一端則只能用于寫,由描述字 fd1來表示,稱其為管道寫端。如果試圖從管道寫端讀取數(shù)據(jù),或者向管道讀端寫入數(shù)據(jù)都將導致錯誤發(fā)生。一般文件的 I/O 函數(shù)都可以用于管道,如 close、read、write 等等。從管道中讀取數(shù)據(jù):如果管道的寫端不存在,則認

7、為已經(jīng)讀到了數(shù)據(jù)的末尾,讀函數(shù)返回的讀出字節(jié)數(shù)為 0;當管道的寫端存在時,如果請求的字節(jié)數(shù)目大于 PIPE_BUF 則返回管道中現(xiàn)有的數(shù)據(jù)字節(jié)數(shù),如果請求的字節(jié)數(shù)目不大于 PIPE_BUF 則返回管道中現(xiàn)有數(shù)據(jù)字節(jié)數(shù)(此時,管道中數(shù)據(jù)量小于請求的數(shù)據(jù)量);或者返回請求的字節(jié)數(shù)(此時,管道中數(shù)據(jù)量不小于請求的數(shù)據(jù)量)。注:(PIPE_BUFBinclude/linux/limits.h 中定義,不同的內核版本可能會有所不同。Posix.1 要求 PIPE_BUF1 少為 512 字節(jié),redhat7.2 中為 4096)。3/65關于管道的讀規(guī)則驗證:/*readtest.c*/#include

8、#include#includemain()(intpipe_fd2;pid_tpid;charr_buf100;charw_buf4;char*p_wbuf;intr_num;intcmd;memset(r_buf,0,sizeof(r_buf);memset(w_buf,0,sizeof(r_buf);p_wbuf=w_buf;if(pipe(pipe_fd)0)(close(pipe_fd0);/readstrcpy(w_buf,111);if(write(pipe_fd1,w_buf,4)!=-1)printf(parentwriteovern);close(pipe_fd1);/wr

9、iteprintf(parentclosefd1overn);sleep(10);/*程序輸出結果:parentwriteoverparentclosefd1overreadnumis4thedatareadfromthepipeis111附加結論:管道寫端關閉后,寫入的數(shù)據(jù)將一直存在,直到讀出為止*I向管道中寫入數(shù)據(jù):向管道中寫入數(shù)據(jù)時,linux 將不保證寫入的原子性,管道緩沖區(qū)一有空閑區(qū)域,寫進程就會試圖向管道寫入數(shù)據(jù)。如果讀進程不讀走管道緩沖區(qū)中的數(shù)據(jù),那么寫操作將一直阻塞。注:只有在管道的讀端存在時,向管道中寫入數(shù)據(jù)才有意義。否則,向管道中寫入數(shù)據(jù)的進程將收到內核傳來的 SIFPIP

10、E 言號,應用程序可以處理該信號,也可以忽略(默認動作則是應用程序終止)。對管道的寫規(guī)則的驗證 1:寫端對讀端存在的依賴性#include#includemain()intpipe_fd2;pid_tpid;charr_buf4;char*w_buf;intwritenum;intcmd;memset(r_buf,0,sizeof(r_buf);if(pipe(pipe_fd)0)(sleep(1);等待子進程完成關閉讀端的操作close(pipe_fd0);/writew_buf=111;if(writenum=write(pipe_fd1,w_buf,4)=-1)printf(writet

11、opipeerrorn);elseprintf(thebyteswritetopipeis%dn,writenum);close(pipe_fd1);)則輸出結果為:Brokenpipe,原因就是該管道以及它的所有 fork()產(chǎn)物的讀端都已經(jīng)被關閉。如果在父進程中保留讀端,即在寫完 pipe 后,再關閉父進程的讀端,也會正常寫入 pipe,讀者可自己驗證一下該結論。因此,在向管道寫入數(shù)據(jù)時,至少應該存在某一個進程,其中管道讀端沒有被關閉,否則就會出現(xiàn)上述錯誤(管道斷裂,進程收到了 SIGPIPE 言號,默認動作是進程終止)對管道的寫規(guī)則的驗證 2:linux 不保證寫管道的原子性驗證#inc

12、lude#include#includemain(intargc,char*argv)(intpipe_fd2;pid_tpid;charr_buf4096;charw_buf4096*2;intwritenum;intrnum;memset(r_buf,0,sizeof(r_buf);if(pipe(pipe_fd)0)(close(pipe_fd0);/writememset(r_buf,0,sizeof(r_buf);if(writenum=write(pipe_fd1,w_buf,1024)=-1)printf(writetopipeerrorn);elseprintf(thebyte

13、swritetopipeis%dn,writenum);writenum=write(pipe_fd1,w_buf,4096);close(pipe_fd1);輸出結果:thebyteswritetopipe1000thebyteswritetopipe1000注意,此行輸出說明了寫入的非原子性thebyteswritetopipe1000thebyteswritetopipe1000thebyteswritetopipe1000thebyteswritetopipe120/注意,此行輸出說明了寫入的非原子性thebyteswritetopipe0thebyteswritetopipe0結論:

14、寫入數(shù)目小于 4096 時寫入是非原子的!如果把父進程中的兩次寫入字節(jié)數(shù)都改為 5000,則很容易得出下面結論:寫入管道的數(shù)據(jù)量大于 4096 字節(jié)時,緩沖區(qū)的空閑空間將被寫入數(shù)據(jù)(補齊),直到寫完所有數(shù)據(jù)為止,如果沒有進程讀數(shù)據(jù),則一直阻塞。1.4 管道應用實例:實例一:用于 shell管道可用于輸入輸出重定向,它將一個命令的輸出直接定向到另一個命令的輸入。比如,當在某個 shell 程序(Bourneshell 或 Cshell 等)鍵入 whowc-l 后,相應 shell 程序將創(chuàng)建 who 以及 wc 兩個進程和這兩個進程間的管道??紤]下面的命令行:$kill-l 運行結果見附$ki

15、ll-l|grepSIGRTMIN 運行結果如下:30)SIGPWR31)SIGSYS32)SIGRTMIN33)SIGRTMIN+1實例二:用于具有親緣關系的進程間通信下面例子給出了管道的具體應用,父進程通過管道發(fā)送一些命令給子進程,子進程解析命令,并根據(jù)命令作相應處理。#include#includemain()intpipe_fd2;pid_tpid;charr_buf4;char*w_buf256;intchildexit=0;inti;intcmd;memset(r_buf,0,sizeof(r_buf);if(pipe(pipe_fd)0)/parent:sendcommandst

16、ochild(close(pipe_fd0);w_buf0=003;w_buf1=005;w_buf2=777;w_buf3=000;for(i=0;i4;i+)write(pipe_fd1,w_bufi,4);close(pipe_fd1);下面是子進程的命令處理函數(shù)(特定于應用):inthandle_cmd(intcmd)(if(cmd256)/supposechildonlysupport256commands(printf(child:invalidcommandn);return-1;printf(child:thecmdfromparentis%dn,cmd);return0;1.

17、5 管道的局限性管道的主要局限性正體現(xiàn)在它的特點上:只支持單向數(shù)據(jù)流;只能用于具有親緣關系的進程之間;沒有名字;管道的緩沖區(qū)是有限的(管道制存在于內存中,在管道創(chuàng)建時,為緩沖區(qū)分配一個頁面大?。?;管道所傳送的是無格式字節(jié)流,這就要求管道的讀出方和寫入方必須事先約定好數(shù)據(jù)的格式,比如多少字節(jié)算作一個消息(或命令、或記錄)等等;2、有名管道概述及相關 API 應用有名管道相關的關鍵概念管道應用的一個重大限制是它沒有名字,因此,只能用于具有親緣關系的進程間通信,在有名管道(namedpipe 或 FIFO)提出后,該限制得到了克服。FIFO 不同于管道之處在于它提供一個路徑名與之關聯(lián),以 FIFO

18、的文件形式存在于文件系統(tǒng)中。這樣,即使與 FIFO 的創(chuàng)建進程不存在親緣關系的進程,只要可以訪問該路徑,就能夠彼此通過 FIFO 相互通信(能夠訪問該路徑的進程以及 FIFO 的創(chuàng)建進程之間),因此,通過 FIFO 不相關的進程也能交換數(shù)據(jù)。值得注意的是,F(xiàn)IFO 嚴格遵循先進先出(firstinfirstout),對管道及 FIFO 的讀總是從開始處返回數(shù)據(jù),對它們的寫則把數(shù)據(jù)添加到末尾。它們不支持諸如 lseek()等文件定位操作。有名管道的創(chuàng)建#include#includeintmkfifo(constchar*pathname,mode_tmode)該函數(shù)的第一個參數(shù)是一個普通白路徑

19、名,也就是創(chuàng)建后 FIFO 的名字。第二個參數(shù)與打開普通文件的 open()函數(shù)中的 mode 參數(shù)相同。如果 mkfifo 的第一個參數(shù)是一個已經(jīng)存在的路徑名時,會返回 EEXIST 錯誤,所以一般典型的調用代碼首先會檢查是否返回該錯誤,如果確實返回該錯誤,那么只要調用打開 FIFO 的函數(shù)就可以了。一般文件的 I/O 函數(shù)都可以用于 FIFO,如 close、read、write 等等。有名管道的打開規(guī)則有名管道比管道多了一個打開操作:open。FIFO 的打開規(guī)則:如果當前打開操作是為讀而打開 FIFO 時,若已經(jīng)有相應進程為寫而打開該 FIFO,則當前打開操作將成功返回;否則,可能阻塞

20、直到有相應進程為寫而打開該 FIFO(當前打開操作設置了阻塞標志);或者,成功返回(當前打開操作沒有設置阻塞標志)。如果當前打開操作是為寫而打開 FIFO 時, 如果已經(jīng)有相應進程為讀而打開該 FIFO,則當前打開操作將成功返回;否則,可能阻塞直到有相應進程為讀而打開該 FIFO(當前打開操作設置了阻塞標志);或者,返回 ENXIO 錯誤(當前打開操作沒有設置阻塞標志)。對打開規(guī)則的驗證參見附 2。有名管道的讀寫規(guī)則從 FIFO 中讀取數(shù)據(jù):約定:如果一個進程為了從 FIFO 中讀取數(shù)據(jù)而阻塞打開 FIFO,那么稱該進程內的讀操作為設置了阻塞標志的讀操作。如果有進程寫打開 FIFO,且當前 F

21、IFO 內沒有數(shù)據(jù),則對于設置了阻塞標志的讀操作來說,將一直阻塞。對于沒有設置阻塞標志讀操作來說則返回-1,當前 errno 值為EAGAIN,提醒以后再試。對于設置了阻塞標志的讀操作說,造成阻塞的原因有兩種:當前 FIFO 內有數(shù)據(jù),但有其它進程在讀這些數(shù)據(jù);另外就是 FIFO 內沒有數(shù)據(jù)。解阻塞的原因則是 FIFO 中有新的數(shù)據(jù)寫入,不論信寫入數(shù)據(jù)量的大小,也不論讀操作請求多少數(shù)據(jù)量。讀打開的阻塞標志只對本進程第一個讀操作施加作用,如果本進程內有多個讀操作序列,則在第一個讀操作被喚醒并完成讀操作后,其它將要執(zhí)行的讀操作將不再阻塞,即使在執(zhí)行讀操作時,F(xiàn)IFO 中沒有數(shù)據(jù)也一樣(此時,讀操作

22、返回 0)。如果沒有進程寫打開 FIFO,則設置了阻塞標志的讀操作會阻塞。注:如果 FIFO 中有數(shù)據(jù),則設置了阻塞標志的讀操作不會因為 FIFO 中的字節(jié)數(shù)小于請求讀的字節(jié)數(shù)而阻塞,此時,讀操作會返回 FIFO 中現(xiàn)有的數(shù)據(jù)量。向 FIFO 中寫入數(shù)據(jù):約定:如果一個進程為了向 FIFO 中寫入數(shù)據(jù)而阻塞打開 FIFO,那么稱該進程內的寫操作為設置了阻塞標志的寫操作。對于設置了阻塞標志的寫操作:當要寫入的數(shù)據(jù)量不大于 PIPE_BUFM,linux 將保證寫入的原子性。如果此時管道空閑緩沖區(qū)不足以容納要寫入的字節(jié)數(shù),則進入睡眠,直到當緩沖區(qū)中能夠容納要寫入的字節(jié)數(shù)時,才開始進行一次性寫操作。

23、當要寫入的數(shù)據(jù)量大于 PIPE_BUF 時,linux 將不再保證寫入的原子性。FIFO 緩沖區(qū)一有空閑區(qū)域,寫進程就會試圖向管道寫入數(shù)據(jù),寫操作在寫完所有請求寫的數(shù)據(jù)后返回。對于沒有設置阻塞標志的寫操作:當要寫入的數(shù)據(jù)量大于 PIPE_BUF 時,linux 將不再保證寫入的原子性。在寫滿所有FIFO 空閑緩沖區(qū)后,寫操作返回。當要寫入的數(shù)據(jù)量不大于 PIPE_BUF 時,linux 將保證寫入的原子性。如果當前 FIFO空閑緩沖區(qū)能夠容納請求寫入的字節(jié)數(shù),寫完后成功返回;如果當前 FIFO 空閑緩沖區(qū)不能夠容納請求寫入的字節(jié)數(shù),則返回 EAGAIN 錯誤,提醒以后再寫;對 FIFO 讀寫規(guī)

24、則的驗證:下面提供了兩個對 FIFO 的讀寫程序,適當調節(jié)程序中的很少地方或者程序的命令行參數(shù)就可以對各種 FIFO 讀寫規(guī)則進行驗證。程序 1:寫 FIFO 的程序#include#include#include#include#defineFIFO_SERVER/tmp/fifoservermain(intargc,char*argv)/參數(shù)為即將寫入的字節(jié)數(shù)intfd;charw_buf4096*2;intreal_wnum;memset(w_buf,0,4096*2);if(mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)0)&(errno!=EEXIST)

25、printf(cannotcreatefifoservern);if(fd=-1)if(errno=ENXIO)printf(openerror;noreadingprocessn);fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);/設置非阻塞標志/fd=open(FIFO_SERVER,O_WRONLY);設置阻塞標志real_wnum=write(fd,w_buf,2048);if(real_wnum=-1)if(errno=EAGAIN)printf(writetofifoerror;trylatern);elseprintf(realwritenu

26、mis%dn,real_wnum);real_wnum=write(fd,w_buf,5000);/5000 用于測試寫入字節(jié)大于 4096 時的非原子性real_wnum=write(fd,w_buf,4096);/4096 用于測試寫入字節(jié)不大于 4096 時的原子性if(real_wnum=-1)if(errno=EAGAIN)printf(trylatern);程序 2:與程序 1 一起測試寫 FIFO 的規(guī)則,第一個命令行參數(shù)是請求從 FIFO 讀出的字節(jié)#include#include#include#include#defineFIFO_SERVER/tmp/fifoserver

27、main(intargc,char*argv)charr_buf4096*2;intfd;intr_size;intret_size;r_size=atoi(argv1);printf(requredrealreadbytes%dn,r_size);memset(r_buf,0,sizeof(r_buf);fd=open(FIFO_SERVER,O_RDONLY|O_NONBLOCK,0);/fd=open(FIFO_SERVER,O_RDONL0);/在此處可以把讀程序編譯成兩個不同版本:阻塞版本及非阻塞版本 if(fd=-1)printf(open%sforreaderrorn);exit

28、();while(1)memset(r_buf,0,sizeof(r_buf);ret_size=read(fd,r_buf,r_size);if(ret_size=-1)if(errno=EAGAIN)printf(nodataavlaiblen);printf(realreadbytes%dn,ret_size);sleep(1);pause();unlink(FIFO_SERVER);程序應用說明:把讀程序編譯成兩個不同版本:阻塞讀版本:br以及非阻塞讀版本 nbr 把寫程序編譯成兩個四個版本:非阻塞且請求寫的字節(jié)數(shù)大于 PIPE_BUF 版本:nbwg非阻塞且請求寫的字節(jié)數(shù)不大于 PI

29、PE_BU 版本:版本 nbw阻塞且請求寫的字節(jié)數(shù)大于 PIPE_BUF 版本:bwg阻塞且請求寫的字節(jié)數(shù)不大于 PIPE_BUF 版本:版本 bw下面將使用 br、nbr、w 代替相應程序中的阻塞讀、非阻塞讀驗證阻塞寫操作:.當請求寫入的數(shù)據(jù)量大于 PIPE_BUFM 的非原子性:onbr1000obwg.當請求寫入的數(shù)據(jù)量不大于 PIPE_BUFM 的原子性:onbr1000obw 驗證非阻塞寫操作:.當請求寫入的數(shù)據(jù)量大于 PIPE_BUFM 的非原子性:onbr1000onbwg.請求寫入的數(shù)據(jù)量不大于 PIPE_BUF 寸的原子性:onbr1000onbw不管寫打開的阻塞標志是否設置

30、,在請求寫入的字節(jié)數(shù)大于 4096 時,都不保證寫入的原子性。但二者有本質區(qū)別:對于阻塞寫來說,寫操作在寫滿 FIFO 的空閑區(qū)域后,會一直等待,直到寫完所有數(shù)據(jù)為止,請求寫入的數(shù)據(jù)最終都會寫入 FIFQ而非阻塞寫則在寫滿 FIFO 的空閑區(qū)域后,就返回(實際寫入白字節(jié)數(shù)),所以有些數(shù)據(jù)最終不能夠寫入。對于讀操作的驗證則比較簡單,不再討論。2.5 有名管道應用實例在驗證了相應的讀寫規(guī)則后,應用實例似乎就沒有必要了。小結:管道常用于兩個方面:(1)在 shell 中時常會用到管道(作為輸入輸入的重定向),在這種應用方式下,管道的創(chuàng)建對于用戶來說是透明的;(2)用于具有親緣關系的進程間通信,用戶自

31、己創(chuàng)建管道,并完成讀寫操作。FIFO 可以說是管道的推廣,克服了管道無名字的限制,使得無親緣關系的進程同樣可以采用先進先出的通信機制進行通信。管道和 FIFO 的數(shù)據(jù)是字節(jié)流,應用程序之間必須事先確定特定的傳輸協(xié)議”,采用傳播具有特定意義的消息。要靈活應用管道及 FIFO,理解它們的讀寫規(guī)則是關鍵。kill-l 的運行結果,顯示了當前系統(tǒng)支持的所有信號1)SIGHUP2)SIGINT3)SIGQUIT4)SIGILL5)SIGTRAP6)SIGABRT7)SIGBUS8)SIGFPE9)SIGKILL0)SIGUSR111)SIGSEGV12)SIGUSR213)SIGPIPE14)SIGAL

32、RM15)SIGTERM17)SIGCHLD18)SIGCONT19)SIGSTOP20)SIGTSTP21)SIGTTIN22)SIGTTOU23)SIGURG24)SIGXCPU25)SIGXFSZ26)SIGVTALRM27)SIGPROF28)SIGWINCH29)SIGIO30)SIGPWR31)SIGSYS32)SIGRTMIN33)SIGRTMIN+1intret;ret=w_open(arg);switch(ret)(case0:34)SIGRTMIN+238)SIGRTMIN+642)SIGRTMIN+10SIGRTMIN+1450)SIGRTMAX-1354)SIGRTMA

33、X-958)SIGRTMAX-562)SIGRTMAX-135)SIGRTMIN+339)SIGRTMIN+743)SIGRTMIN+11SIGRTMIN+1551)SIGRTMAX-1255)SIGRTMAX-859)SIGRTMAX-463)SIGRTMAX36)SIGRTMIN+440)SIGRTMIN+8SIGRTMIN+1248)SIGRTMAX-1552)SIGRTMAX-1156)SIGRTMAX-760)SIGRTMAX-337)SIGRTMIN+541)SIGRTMIN+9SIGRTMIN+1349)SIGRTMAX-1453)SIGRTMAX-1057)SIGRTMAX-6

34、61)SIGRTMAX-2除了在此處用來說明管道應用外,接下來的專題還要對這些信號分類討論。對 FIFO 打開規(guī)則的驗證(主要驗證寫打開對讀打開的依賴性)#include#include#include#include#defineFIFO_SERVER/tmp/fifoserverinthandle_client(char*);main(intargc,char*argv)intr_rd;intw_fd;pid_tpid;if(mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)0)&(errno!=EEXIST)printf(cannotcreatefifoserv

35、ern);handle_client(FIFO_SERVER);inthandle_client(char*arg)(printf(open%serrorn,arg);printf(noprocesshasthefifoopenforreadingn);return-1;case-1:(printf(somethingwrongwithopenthefifoexceptforENXIO);return-1;case1:(printf(openserverokn);return1;default:(printf(w_no_rreturn-n);return0;unlink(FIFO_SERVER

36、);intw_open(char*arg)0openerrorfornoreading-1openerrorforotherreasons1openok(if(open(arg,O_WRONLY|O_NONBLOCK,0)=-1)if(errno=ENXIO)(return0;elsereturn-1;return1;Linux環(huán)境進程間通信(二):信號(上)1、信號及信號來源信號本質信號是在軟件層次上對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一個中斷請求可以說是一樣的。信號是異步的,一個進程不必通過任何操作來等待信號的到達,事實上,進程也不知道信號到底什么時候到達。信號

37、是進程間通信機制中唯一的異步通信機制,可以看作是異步通知,通知接收信號的進程有哪些事情發(fā)生了。信號機制經(jīng)過 POSIX 實時擴展后,功能更加強大,除了基本通知功能外,還可以傳遞附加信息。信號來源信號事件的發(fā)生有兩個來源:硬件來源(比如我們按下了鍵盤或者其它硬件故障);軟件來源,最常用發(fā)送信號的系統(tǒng)函數(shù)是 kill,raise,alarm 和 setitimer 以及 sigqueue 函數(shù), 軟件來源還包括一些非法運算等操作。2、信號的種類可以從兩個不同的分類角度對信號進行分類:(1)可靠性方面:可靠信號與不可靠信號;(2)與時間的關系上:實時信號與非實時信號。在Linux 環(huán)境進程間通信(一

38、):管道及有名管道的附 1 中列出了系統(tǒng)所支持的所有信號??煽啃盘柵c不可靠信號“不可靠信號Linux 信號機制基本上是從 Unix 系統(tǒng)中繼承過來的。 早期 Unix 系統(tǒng)中的信號機制比較簡單和原始, 后來在實踐中暴露出一些問題,因此,把那些建立在早期機制上的信號叫做不可靠信號”,信號值小于 SIGRTMIN(Redhat7.2 中,SIGRTMIN=32,SIGRTMAX=63 的信號都是不可靠信號。這就是不可靠信號”的來源。它的主要問題是:進程每次處理信號后,就將對信號的響應設置為默認動作。在某些情況下,將導致對信號的錯誤處理;因此,用戶如果不希望這樣的操作,那么就要在信號處理函數(shù)結尾再一

39、次調用 signal。,重新安裝該信號。信號可能丟失,后面將對此詳細闡述。因此, 早期 unix 下的不可靠信號主要指的是進程可能對信號做出錯誤的反應以及信號可能丟失。Linux 支持不可靠信號,但是對不可靠信號機制做了改進:在調用完信號處理函數(shù)后,不必重新調用該信號的安裝函數(shù)(信號安裝函數(shù)是在可靠機制上的實現(xiàn))。因此,Linux 下的不可靠信號問題主要指的是信號可能丟失??煽啃盘栯S著時間的發(fā)展,實踐證明了有必要對信號的原始機制加以改進和擴充。所以,后來出現(xiàn)的各種 Unix 版本分別在這方面進行了研究,力圖實現(xiàn)可靠信號。由于原來定義的信號已有許多應用,不好再做改動,最終只好又新增加了一些信號,

40、并在一開始就把它們定義為可靠信號, 這些信號支持排隊, 不會丟失。 同時, 信號的發(fā)送和安裝也出現(xiàn)了新版本: 信號發(fā)送函數(shù) sigqueue()及信號安裝函數(shù) sigaction()。POSIX.4 對可靠信號機制做了標準化。但是,POSIX只對可靠信號機制應具有的功能以及信號機制的對外接口做了標準化,對信號機制的實現(xiàn)沒有作具體的規(guī)定。信號值位于 SIGRTMIN 和 SIGRTMAX 之間的信號都是可靠信號, 可靠信號克服了信號可能丟失的問題。Linux 在支持新版本的彳 t 號安裝函數(shù) sigation()以及信號發(fā)送函數(shù) sigqueue()的同時,仍然支持早期的 signal()信號安

41、裝函數(shù),支持信號發(fā)送函數(shù) kill()。注:不要有這樣的誤解:由 sigqueue()發(fā)送、sigaction 安裝的信號就是可靠的。事實上,可靠信號是指后來添加的新信號(信號值位于 SIGRTMIN 及 SIGRTMAX 之間);不可靠信號是信號值小于 SIGRTMIN 的信號。信號的可靠與不可靠只與信號值有關,與信號的發(fā)送及安裝函數(shù)無關。目前 linux 中的 signal()是通過 sigation()函數(shù)實現(xiàn)的,因此,即使通過 signal()安裝的信號,在信號處理函數(shù)的結尾也不必再調用一次信號安裝函數(shù)。同時,由 signal()安裝的實時信號支持排隊,同樣不會丟失。對于目前 linux 的兩個信號安裝函數(shù):signal()及 sigaction()來說,它們都不能把 SIGRTMIN 以前的信號變成可靠信號(都不支持排隊,仍有可能丟失,仍然是不可靠信號),而且對 SIGRTMIN 以后的信號都支持排隊。這兩個函數(shù)的最大區(qū)別在于,經(jīng)過 sigaction 安裝的信號都能傳遞信息給信號處理函數(shù)(對所有信號這一點都成立),而經(jīng)過 signal 安裝的信號卻不能向信號處理函數(shù)傳遞信息。對于信號發(fā)送函數(shù)來說也是一樣的。實時信號與非實時信號早期Unix系統(tǒng)只定義了32種信號, Rethat7.2支持64種信號, 編號0-63(SIGRTMIN=31

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論