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

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

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

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

3、1、消息隊(duì)列基本概念 342、操作消息隊(duì)列 35消息隊(duì)列 API 363、消息隊(duì)列的限制 384、消息隊(duì)列應(yīng)用實(shí)例 39小結(jié): 415 Linux 環(huán)境進(jìn)程間通信(四):信號(hào)燈 441、信號(hào)燈概述 442、 Linux 信號(hào)燈 443、信號(hào)燈與內(nèi)核 444、操作信號(hào)燈 455、信號(hào)燈的限制 486、競(jìng)爭(zhēng)問(wèn)題 487、信號(hào)燈應(yīng)用實(shí)例 496 Linux 環(huán)境進(jìn)程間通信(五):共享內(nèi)存(上) 531、 內(nèi)核怎樣保證各個(gè)進(jìn)程尋址到同一個(gè)共享內(nèi)存區(qū)域的內(nèi)存頁(yè)面 542、 mmap() 及其相關(guān)系統(tǒng)調(diào)用 542.1 mmap() 系統(tǒng)調(diào)用形式 552.2 系統(tǒng)調(diào)用mmap() 用于共享內(nèi)存的兩種方式 5

4、52.3 系統(tǒng)調(diào)用munmap() 552.4 系統(tǒng)調(diào)用msync() 553、 mmap() 范例 56范例 1 :兩個(gè)進(jìn)程通過(guò)映射普通文件實(shí)現(xiàn)共享內(nèi)存通信 56范例 2 :父子進(jìn)程通過(guò)匿名映射實(shí)現(xiàn)共享內(nèi)存 584、對(duì) mmap()返回地址的訪問(wèn) 59結(jié)論 617 Linux 環(huán)境進(jìn)程間通信(五) :共享內(nèi)存(下) 611、系統(tǒng)V共享內(nèi)存原理 622、系統(tǒng) V 共享內(nèi)存 API 633、系統(tǒng)V共享內(nèi)存限制 644、系統(tǒng)V共享內(nèi)存范例 64結(jié)論 6650 / 66Linux環(huán)境進(jìn)程間通信(一):管道及有名管道1、管道概述及相關(guān)API應(yīng)用1.1 管道相關(guān)的關(guān)鍵概念管道是Linux支持的最初Uni

5、x IPC形式之一,具有以下特點(diǎn):? 管道是半雙工的,數(shù)據(jù)只能向一個(gè)方向流動(dòng);需要雙方通信時(shí),需要建立起兩個(gè)管 道;? 只能用于父子進(jìn)程或者兄弟進(jìn)程之間(具有親緣關(guān)系的進(jìn)程);? 單獨(dú)構(gòu)成一種獨(dú)立的文件系統(tǒng):管道對(duì)于管道兩端的進(jìn)程而言,就是一個(gè)文件,但 它不是普通的文件,它不屬于某種文件系統(tǒng),而是自立門戶,單獨(dú)構(gòu)成一種文件系 統(tǒng),并且只存在與內(nèi)存中。? 數(shù)據(jù)的讀出和寫入:一個(gè)進(jìn)程向管道中寫的內(nèi)容被管道另一端的進(jìn)程讀出。寫入的 內(nèi)容每次都添加在管道緩沖區(qū)的末尾,并且每次都是從緩沖區(qū)的頭部讀出數(shù)據(jù)。1.2 管道的創(chuàng)建:#include <unistd.h>int pipe(int fd

6、2)該函數(shù)創(chuàng)建的管道的兩端處于一個(gè)進(jìn)程中間,在實(shí)際應(yīng)用中沒(méi)有太大意義,因此,一個(gè)進(jìn)程在由pipe()創(chuàng)建管道后,一般再fork 一個(gè)子進(jìn)程,然后通過(guò)管道實(shí)現(xiàn)父子進(jìn)程間的通信(因 此也不難推出,只要兩個(gè)進(jìn)程中存在親緣關(guān)系,這里的親緣關(guān)系指的是具有共同的祖先,都可以采用管道方式來(lái)進(jìn)行通信)。1.3 管道的讀寫規(guī)則:管道兩端可分別用描述字fd0以及fd1來(lái)描述,需要注意的是,管道的兩端是固定了任務(wù)的。即一端只能用于讀,由描述字fd0表示,稱其為管道讀端;另一端則只能用于寫,由描述字fd1來(lái)表示,稱其為管道寫端。如果試圖從管道寫端讀取數(shù)據(jù),或者向管道讀端寫 入數(shù)據(jù)都將導(dǎo)致錯(cuò)誤發(fā)生。一般文件的I/O函數(shù)

7、都可以用于管道,如 close、read、write等等。從管道中讀取數(shù)據(jù):? 如果管道的寫端不存在,則認(rèn)為已經(jīng)讀到了數(shù)據(jù)的末尾,讀函數(shù)返回的讀出字節(jié)數(shù) 為0;?當(dāng)管道的寫端存在時(shí),如果請(qǐng)求的字節(jié)數(shù)目大于PIPE_BUF則返回管道中現(xiàn)有的數(shù)據(jù)字節(jié)數(shù),如果請(qǐng)求的字節(jié)數(shù)目不大于PIPE_BUF則返回管道中現(xiàn)有數(shù)據(jù)字節(jié)數(shù)(此時(shí),管道中數(shù)據(jù)量小于請(qǐng)求的數(shù)據(jù)量);或者返回請(qǐng)求的字節(jié)數(shù)(此時(shí),管道中數(shù)據(jù) 量不小于請(qǐng)求的數(shù)據(jù)量)。注:(PIPE_BUFB include/linux/limits.h 中定義,不同的內(nèi) 核版本可能會(huì)有所不同。Posix.1要求PIPE_BUF至少為512字節(jié),red hat

8、7.2中為4096)。關(guān)于管道的讀規(guī)則驗(yàn)證:* readtest.c */<unistd.h>#include <sys/types.h>#include <errno.h> main()int pipe_fd2;pid_t pid;char r_buf100;char w_buf4;char* p_wbuf; int r_num;int cmd;memset(r_buf,0,sizeof(r_buf);memset(w_buf,0,sizeof(r_buf);p_wbuf=w_buf;if(pipe(pipe_fd)<0)printf("p

9、ipe create errorn"); return -1;if(pid=fork()=0)printf("n");close(pipe_fd1);sleep(3);/確保父進(jìn)程關(guān)閉寫端r_num=read(pipe_fd0,r_buf,100);printf( "read num is %d the data read from the pipe is %dn",r_num,atoi(r_buf);close(pipe_fd0);exit();else if(pid>0)close(pipe_fd0);/readstrcpy(w_bu

10、f,"111");if(write(pipe_fd1,w_buf,4)!=-1)printf("parent write overn");close(pipe_fd1);writeprintf("parent close fd1 overn");sleep(10);/* 程序輸出結(jié)果:* parent write over* parent close fd1 over* read num is 4 the data read from the pipe is 111* 附加結(jié)論:* 管道寫端關(guān)閉后,寫入的數(shù)據(jù)將一直存在,直到讀出為止*

11、 I向管道中寫入數(shù)據(jù):?向管道中寫入數(shù)據(jù)時(shí),linux將不保證寫入的原子性,管道緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程就會(huì)試圖向管道寫入數(shù)據(jù)。如果讀進(jìn)程不讀走管道緩沖區(qū)中的數(shù)據(jù),那么寫操 作將一直阻塞。注:只有在管道的讀端存在時(shí),向管道中寫入數(shù)據(jù)才有意義。否則,向管道中寫入數(shù)據(jù)的進(jìn)程將收到內(nèi)核傳來(lái)的SIFPIPE言號(hào),應(yīng)用程序可以處理該信號(hào),也可以忽略(默認(rèn)動(dòng)作則是應(yīng)用程序終止)。對(duì)管道的寫規(guī)則的驗(yàn)證1:寫端對(duì)讀端存在的依賴性#include <unistd.h>#include <sys/types.h>main()int pipe_fd2;pid_t pid;char r_bu

12、f4;char* w_buf;int writenum;int cmd;memset(r_buf,0,sizeof(r_buf);if(pipe(pipe_fd)<0)printf("pipe create errorn");return -1;if(pid=fork()=0)close(pipe_fd0); close(pipe_fd1);sleep(10); exit();else if(pid>0) sleep(1); 等待子進(jìn)程完成關(guān)閉讀端的操作close(pipe_fd0);write w_buf="111"if(writenum=

13、write(pipe_fd1,w_buf,4)=-1) printf("write to pipe errorn");elseprintf("the bytes write to pipe is %d n", writenum);close(pipe_fd1); 則輸出結(jié)果為:Broken pipe,原因就是該管道以及它的所有fork()產(chǎn)物的讀端都已經(jīng)被關(guān)閉。如果在父進(jìn)程中保留讀端,即在寫完 pipe后,再關(guān)閉父進(jìn)程的讀端,也會(huì)正常寫入 pipe, 讀者可自己驗(yàn)證一下該結(jié)論。因此,在向管道寫入數(shù)據(jù)時(shí),至少應(yīng)該存在某一個(gè)進(jìn)程,其中管道讀端沒(méi)有被關(guān)閉,否則

14、就會(huì)出現(xiàn)上述錯(cuò)誤(管道斷裂,進(jìn)程收到了 SIGPIPE言號(hào),默認(rèn)動(dòng)作是進(jìn)程終止) 對(duì)管道的寫規(guī)則的驗(yàn)證2: linux不保證寫管道的原子性驗(yàn)證#include <unistd.h>#include <sys/types.h>#include <errno.h>main(int argc,char*argv) int pipe_fd2;pid_t pid;char r_buf4096;char w_buf4096*2;int writenum;int rnum;memset(r_buf,0,sizeof(r_buf);if(pipe(pipe_fd)<0

15、) printf("pipe create errorn");return -1;if(pid=fork()=0) close(pipe_fd1);while(1)sleep;rnum=read(pipe_fd0,r_buf,1000);printf("child: readnum is %dn",rnum);close(pipe_fd0);exit();else if(pid>0)close(pipe_fd0);writememset(r_buf,0,sizeof(r_buf);if(writenum=write(pipe_fd1,w_buf,1

16、024)=-1)printf("write to pipe errorn");elseprintf("the bytes write to pipe is %d n", writenum);writenum=write(pipe_fd1,w_buf,4096);close(pipe_fd1);輸出結(jié)果:the bytes write to pipe 1000the bytes write to pipe 1000/注意,此行輸出說(shuō)明了寫入的非原子性the bytes write to pipe 1000the bytes write to pipe 10

17、00the bytes write to pipe 1000the bytes write to pipe 120/注意,此行輸出說(shuō)明了寫入的非原子性the bytes write to pipe 0the bytes write to pipe 0結(jié)論:寫入數(shù)目小于4096時(shí)寫入是非原子的!如果把父進(jìn)程中的兩次寫入字節(jié)數(shù)都改為5000 ,則很容易得出下面結(jié)論:寫入管道的數(shù)據(jù)量大于 4096字節(jié)時(shí),緩沖區(qū)的空閑空間將被寫入數(shù)據(jù) (補(bǔ)齊),直到寫完所 有數(shù)據(jù)為止,如果沒(méi)有進(jìn)程讀數(shù)據(jù),則一直阻塞。1.4管道應(yīng)用實(shí)例:實(shí)例一:用于 shell管道可用于輸入輸出重定向,它將一個(gè)命令的輸出直接定向到另一

18、個(gè)命令的輸入。比如,當(dāng)在某個(gè)shell程序(Bourne shell或C shell等)鍵入 who wc -l后,相應(yīng)shell程序?qū)?chuàng)建 who 以及wc兩個(gè)進(jìn)程和這兩個(gè)進(jìn)程間的管道??紤]下面的命令行:$kill -l運(yùn)行結(jié)果見附 $kill -l | grep SIGRTMIN 運(yùn)行結(jié)果如下:30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+134) SIGRTMIN+238) SIGRTMIN+642) SIGRTMIN+1046) SIGRTMIN+1435) SIGRTMIN+339) SIGRTMIN+743) SIGRTMIN+11

19、47) SIGRTMIN+1536) SIGRTMIN+4 37) SIGRTMIN+540) SIGRTMIN+8 41) SIGRTMIN+944) SIGRTMIN+12 45) SIGRTMIN+1348) SIGRTMAX-15 49) SIGRTMAX-14實(shí)例二:用于具有親緣關(guān)系的進(jìn)程間通信下面例子給出了管道的具體應(yīng)用,父進(jìn)程通過(guò)管道發(fā)送一些命令給子進(jìn)程,子進(jìn)程解析命令,并根據(jù)命令作相應(yīng)處理。#include <unistd.h>#include <sys/types.h>main()int pipe_fd2;pid_t pid;char r_buf4;c

20、har* w_buf256;int childexit=0;int i;int cmd;memset(r_buf,0,sizeof(r_buf);if(pipe(pipe_fd)<0) printf("pipe create errorn"); return -1;if(pid=fork()=0)子進(jìn)程:解析從管道中獲取的命令,并作相應(yīng)的處理printf("n");close(pipe_fd1);sleep(2);while(!childexit)read(pipe_fd0,r_buf,4);cmd=atoi(r_buf);if(cmd=0)pri

21、ntf("child: receive command from parent overn now child process exitn"); childexit=1;else if(handle_cmd(cmd)!=0) return;sleep(1);close(pipe_fd0);exit();else if(pid>0)/parent: send commands to childclose(pipe_fd0);w_buf0="003"w_buf1="005"w_buf2="777"w_buf3=&

22、quot;000"for(i=0;i<4;i+)write(pipe_fd1,w_bufi,4);close(pipe_fd1);下面是子進(jìn)程的命令處理函數(shù)(特定于應(yīng)用):int handle_cmd(int cmd)if(cmd<0)|(cmd>256)/suppose child only support 256 commandsprintf("child: invalid command n");return -1;printf("child: the cmd from parent is %dn", cmd);retu

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

24、供一個(gè)路徑名與之關(guān)聯(lián),以FIFO的文件形式存在于文件系統(tǒng)中。這樣,即使與FIFO的創(chuàng)建進(jìn)程不存在親緣關(guān)系的進(jìn)程,只要可以訪問(wèn)該路徑,就能夠彼此通過(guò)FIFO相互通信(能夠訪問(wèn)該路徑的進(jìn)程以及FIFO的創(chuàng)建進(jìn)程之間),因此,通過(guò) FIFO不相關(guān)的進(jìn)程也能交換數(shù)據(jù)。值得注意的是,F(xiàn)IFO嚴(yán)格遵循先進(jìn)先出(first in first out ),對(duì)管道及FIFO的讀總是從開 始處返回?cái)?shù)據(jù),對(duì)它們的寫則把數(shù)據(jù)添加到末尾。它們不支持諸如lseek()等文件定位操作。2.2 有名管道的創(chuàng)建#include <sys/types.h>#include <sys/stat.h>int

25、mkfifo(const char * pathname, mode_t mode)該函數(shù)的第一個(gè)參數(shù)是一個(gè)普通白路徑名,也就是創(chuàng)建后FIFO的名字。第二個(gè)參數(shù)與打開普通文件的open()函數(shù)中的mode參數(shù)相同。如果 mkfifo的第一個(gè)參數(shù)是一個(gè)已經(jīng)存在的 路徑名時(shí),會(huì)返回EEXIST錯(cuò)誤,所以一般典型的調(diào)用代碼首先會(huì)檢查是否返回該錯(cuò)誤,如果確實(shí)返回該錯(cuò)誤,那么只要調(diào)用打開FIFO的函數(shù)就可以了。一般文件的I/O函數(shù)都可以用于 FIFO,如 close、read、write 等等。2.3 有名管道的打開規(guī)則有名管道比管道多了一個(gè)打開操作:open。FIFO的打開規(guī)則:如果當(dāng)前打開操作是為讀

26、而打開FIFO時(shí),若已經(jīng)有相應(yīng)進(jìn)程為寫而打開該FIFO,則當(dāng)前打開操作將成功返回;否則,可能阻塞直到有相應(yīng)進(jìn)程為寫而打開該FIFO (當(dāng)前打開操作設(shè)置了阻塞標(biāo)志);或者,成功返回(當(dāng)前打開操作沒(méi)有設(shè)置阻塞標(biāo)志)。如果當(dāng)前打開操作是為寫而打開 FIFO時(shí),如果已經(jīng)有相應(yīng)進(jìn)程為讀而打開該 FIFO,則當(dāng)前 打開操作將成功返回;否則,可能阻塞直到有相應(yīng)進(jìn)程為讀而打開該FIFO (當(dāng)前打開操作設(shè)置了阻塞標(biāo)志);或者,返回ENXIO錯(cuò)誤(當(dāng)前打開操作沒(méi)有設(shè)置阻塞標(biāo)志) 。對(duì)打開規(guī)則的驗(yàn)證參見附2。2.4 有名管道的讀寫規(guī)則從FIFO中讀取數(shù)據(jù):約定:如果一個(gè)進(jìn)程為了從FIFO中讀取數(shù)據(jù)而阻塞打開 FIF

27、O,那么稱該進(jìn)程內(nèi)的讀操作為設(shè)置了阻塞標(biāo)志的讀操作。? 如果有進(jìn)程寫打開 FIFO,且當(dāng)前FIFO內(nèi)沒(méi)有數(shù)據(jù),則對(duì)于設(shè)置了阻塞標(biāo)志的讀操作 來(lái)說(shuō),將一直阻塞。對(duì)于沒(méi)有設(shè)置阻塞標(biāo)志讀操作來(lái)說(shuō)則返回-1,當(dāng)前errno值為EAGAIN,提醒以后再試。? 對(duì)于設(shè)置了阻塞標(biāo)志的讀操作說(shuō),造成阻塞的原因有兩種:當(dāng)前FIFO內(nèi)有數(shù)據(jù),但有其它進(jìn)程在讀這些數(shù)據(jù);另外就是FIFO內(nèi)沒(méi)有數(shù)據(jù)。解阻塞的原因則是 FIFO中有新的數(shù)據(jù)寫入,不論信寫入數(shù)據(jù)量的大小,也不論讀操作請(qǐng)求多少數(shù)據(jù)量。? 讀打開的阻塞標(biāo)志只對(duì)本進(jìn)程第一個(gè)讀操作施加作用,如果本進(jìn)程內(nèi)有多個(gè)讀操作 序列,則在第一個(gè)讀操作被喚醒并完成讀操作后,其它

28、將要執(zhí)行的讀操作將不再阻 塞,即使在執(zhí)行讀操作時(shí),F(xiàn)IFO中沒(méi)有數(shù)據(jù)也一樣(此時(shí),讀操作返回0)。? 如果沒(méi)有進(jìn)程寫打開 FIFO,則設(shè)置了阻塞標(biāo)志的讀操作會(huì)阻塞。注:如果FIFO中有數(shù)據(jù),則設(shè)置了阻塞標(biāo)志的讀操作不會(huì)因?yàn)镕IFO中的字節(jié)數(shù)小于請(qǐng)求讀的字節(jié)數(shù)而阻塞,此時(shí),讀操作會(huì)返回FIFO中現(xiàn)有的數(shù)據(jù)量。向FIFO中寫入數(shù)據(jù):約定:如果一個(gè)進(jìn)程為了向FIFO中寫入數(shù)據(jù)而阻塞打開 FIFO,那么稱該進(jìn)程內(nèi)的寫操作為設(shè)置了阻塞標(biāo)志的寫操作。對(duì)于設(shè)置了阻塞標(biāo)志的寫操作:? 當(dāng)要寫入的數(shù)據(jù)量不大于PIPE_BUF寸,linux將保證寫入的原子性。如果此時(shí)管道空閑緩沖區(qū)不足以容納要寫入的字節(jié)數(shù),則進(jìn)入

29、睡眠,直到當(dāng)緩沖區(qū)中能夠容納要寫 入的字節(jié)數(shù)時(shí),才開始進(jìn)行一次性寫操作。? 當(dāng)要寫入的數(shù)據(jù)量大于PIPE_BUF時(shí),linux將不再保證寫入的原子性。FIFO緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程就會(huì)試圖向管道寫入數(shù)據(jù),寫操作在寫完所有請(qǐng)求寫的數(shù)據(jù) 后返回。對(duì)于沒(méi)有設(shè)置阻塞標(biāo)志的寫操作:? 當(dāng)要寫入的數(shù)據(jù)量大于PIPE_BUF時(shí),linux將不再保證寫入的原子性。在寫滿所有FIFO空閑緩沖區(qū)后,寫操作返回。? 當(dāng)要寫入的數(shù)據(jù)量不大于PIPE_BUF時(shí),linux將保證寫入的原子性。如果當(dāng)前FIFO空閑緩沖區(qū)能夠容納請(qǐng)求寫入的字節(jié)數(shù),寫完后成功返回;如果當(dāng)前FIFO空閑緩沖區(qū)不能夠容納請(qǐng)求寫入的字節(jié)數(shù),則返

30、回EAGAIN錯(cuò)誤,提醒以后再寫;對(duì)FIFO讀寫規(guī)則的驗(yàn)證:下面提供了兩個(gè)對(duì) FIFO的讀寫程序,適當(dāng)調(diào)節(jié)程序中的很少地方或者程序的命令行參數(shù)就可以對(duì)各種FIFO讀寫規(guī)則進(jìn)行驗(yàn)證。程序1 :寫FIFO的程序#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#define FIFO_SERVER "/tmp/fifoserver"main(int argc,char* argv)/參數(shù)為即將寫入的字節(jié)數(shù)int fd;cha

31、r w_buf4096*2;int real_wnum;memset(w_buf,0,4096*2);if(mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST) printf("cannot create fifoservern");if(fd=-1)if(errno=ENXIO)printf("open error; no reading processn");fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);/設(shè)置非阻塞標(biāo)志fd=open

32、(FIFO_SERVER,O_WRONLY);設(shè)置阻塞標(biāo)志real_wnum=write(fd,w_buf,2048);if(real_wnum=-1)if(errno=EAGAIN)printf("write to fifo error; try latern");elseprintf("real write num is %dn",real_wnum);real_wnum=write(fd,w_buf,5000);/5000用于測(cè)試寫入字節(jié)大于4096時(shí)的非原子性real_wnum=write(fd,w_buf,4096);/4096用于測(cè)試寫入字節(jié)

33、不大于4096時(shí)的原子性if(real_wnum=-1)if(errno=EAGAIN)printf("try later'n");程序2:與程序1 一起測(cè)試寫FIFO的規(guī)則,第一個(gè)命令行參數(shù)是請(qǐng)求從FIFO讀出的字節(jié)#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#define FIFO_SERVER "/tmp/fifoserver"main(int argc,char* argv)ch

34、ar r_buf4096*2;int fd;int r_size;int ret_size;r_size=atoi(argv1);printf("requred real read bytes %dn",r_size);memset(r_buf,0,sizeof(r_buf);fd=open(FIFO_SERVER,O_RDONLY|O_NONBLOCK,0);fd=open(FIFO_SERVER,O_RDONL8;/在此處可以把讀程序編譯成兩個(gè)不同版本:阻塞版本及非阻塞版本 if(fd=-1)printf("open %s for read errorn&qu

35、ot;);exit();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("no data avlaiblen");printf("real read bytes %dn",ret_size);sleep(1);pause();unlink(FIFO_SERVER);程序應(yīng)用說(shuō)明:把讀程序編譯成兩個(gè)不同版本:?阻塞讀版本:br? 以及非阻塞讀版本nbr把寫程序編譯成兩個(gè)四個(gè)版本:?非阻塞且請(qǐng)求寫

36、的字節(jié)數(shù)大于PIPE_BUF版本:nbwg?非阻塞且請(qǐng)求寫的字節(jié)數(shù)不大于PIPE_BU版本:版本nbw?阻塞且請(qǐng)求寫的字節(jié)數(shù)大于PIPE_BUF版本:bwg?阻塞且請(qǐng)求寫的字節(jié)數(shù)不大于PIPE_BUF版本:版本bw下面將使用br、 nbr 、 w 代替相應(yīng)程序中的阻塞讀、非阻塞讀驗(yàn)證阻塞寫操作:1 .當(dāng)請(qǐng)求寫入的數(shù)據(jù)量大于PIPE_BUFM的非原子性:o nbr 1000 o bwg2 .當(dāng)請(qǐng)求寫入的數(shù)據(jù)量不大于PIPE_BUFM的原子性:o nbr 1000 o bw驗(yàn)證非阻塞寫操作:1 .當(dāng)請(qǐng)求寫入的數(shù)據(jù)量大于PIPE_BUFM的非原子性:o nbr 1000 o nbwg2 .請(qǐng)求寫入的

37、數(shù)據(jù)量不大于PIPE_BUF寸的原子性:o nbr 1000 o nbw不管寫打開的阻塞標(biāo)志是否設(shè)置,在請(qǐng)求寫入的字節(jié)數(shù)大于4096 時(shí),都不保證寫入的原子性。但二者有本質(zhì)區(qū)別:對(duì)于阻塞寫來(lái)說(shuō),寫操作在寫滿FIFO的空閑區(qū)域后,會(huì)一直等待,直到寫完所有數(shù)據(jù)為止,請(qǐng)求寫入的數(shù)據(jù)最終都會(huì)寫入FIFO;而非阻塞寫則在寫滿FIFO的空閑區(qū)域后,就返回(實(shí)際寫入白字節(jié)數(shù)),所以有些數(shù)據(jù)最終不能夠?qū)懭?。?duì)于讀操作的驗(yàn)證則比較簡(jiǎn)單,不再討論。2.5有名管道應(yīng)用實(shí)例在驗(yàn)證了相應(yīng)的讀寫規(guī)則后,應(yīng)用實(shí)例似乎就沒(méi)有必要了。小結(jié):管道常用于兩個(gè)方面: ( 1 )在 shell 中時(shí)常會(huì)用到管道(作為輸入輸入的重定向)

38、 ,在這種應(yīng)用方式下, 管道的創(chuàng)建對(duì)于用戶來(lái)說(shuō)是透明的;( 2)用于具有親緣關(guān)系的進(jìn)程間通信,用戶自己創(chuàng)建管道,并完成讀寫操作。FIFO 可以說(shuō)是管道的推廣,克服了管道無(wú)名字的限制,使得無(wú)親緣關(guān)系的進(jìn)程同樣可以采 用先進(jìn)先出的通信機(jī)制進(jìn)行通信。管道和 FIFO 的數(shù)據(jù)是字節(jié)流,應(yīng)用程序之間必須事先確定特定的傳輸"協(xié)議 " ,采用傳播具有特定意義的消息。要靈活應(yīng)用管道及 FIFO,理解它們的讀寫規(guī)則是關(guān)鍵。kill-l的運(yùn)行結(jié)果,顯示了當(dāng)前系統(tǒng)支持的所有信號(hào)1) SIGHUP2) SIGINT3) SIGQUIT 4) SIGILL5) SIGTRAP6) SIGABRT 7

39、) SIGBUS8) SIGFPE 9) SIGKILL 0) SIGUSR1 11) SIGSEGV 12) SIGUSR213) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+

40、1 int ret;34) SIGRTMIN+238) SIGRTMIN+642) SIGRTMIN+1046) SIGRTMIN+1450) SIGRTMAX-1354) SIGRTMAX-958) SIGRTMAX-562) SIGRTMAX-135) SIGRTMIN+339) SIGRTMIN+743) SIGRTMIN+1147) SIGRTMIN+1551) SIGRTMAX-1255) SIGRTMAX-859) SIGRTMAX-463) SIGRTMAX36) SIGRTMIN+440) SIGRTMIN+844) SIGRTMIN+1248) SIGRTMAX-1552)

41、SIGRTMAX-1156) SIGRTMAX-760) SIGRTMAX-337) SIGRTMIN+541) SIGRTMIN+945) SIGRTMIN+1349) SIGRTMAX-1453) SIGRTMAX-1057) SIGRTMAX-661) SIGRTMAX-2除了在此處用來(lái)說(shuō)明管道應(yīng)用外,接下來(lái)的專題還要對(duì)這些信號(hào)分類討論。對(duì)FIFO打開規(guī)則的驗(yàn)證(主要驗(yàn)證寫打開對(duì)讀打開的依賴性)#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.

42、h>#define FIFO_SERVER "/tmp/fifoserver" int handle_client(char*);main(int argc,char* argv)int r_rd;int w_fd;pid_t pid;if(mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST) printf("cannot create fifoservern");handle_client(FIFO_SERVER);int handle_client(char* arg

43、)ret=w_open(arg);switch(ret)case 0:printf("open %s errorn",arg);printf("no process has the fifo open for readingn");return -1;case -1:printf("something wrong with open the fifo except for ENXIO"); return -1;case 1:printf("open server okn");return 1;default:pri

44、ntf("w_no_r return -n");return 0;unlink(FIFO_SERVER);int w_open(char*arg)/ 0 open error for no reading-1 open error for other reasons1 open okif(open(arg,O_WRONLY|O_NONBLOCK,0)=-1) if(errno=ENXIO)return 0;elsereturn -1;return 1;Linux 環(huán)境進(jìn)程間通信(二):信號(hào)(上)1 、信號(hào)及信號(hào)來(lái)源1.1 信號(hào)本質(zhì)信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬, 在

45、原理上, 一個(gè)進(jìn)程收到一個(gè)信號(hào)與處理器收到一個(gè)中斷請(qǐng)求可以說(shuō)是一樣的。 信號(hào)是異步的, 一個(gè)進(jìn)程不必通過(guò)任何操作來(lái)等待信號(hào)的到達(dá),事實(shí)上,進(jìn)程也不知道信號(hào)到底什么時(shí)候到達(dá)。信號(hào)是進(jìn)程間通信機(jī)制中唯一的異步通信機(jī)制, 可以看作是異步通知, 通知接收信號(hào)的進(jìn)程有哪些事情發(fā)生了。信號(hào)機(jī)制經(jīng)過(guò)POSI雙時(shí)擴(kuò)展后,功能更加強(qiáng)大,除了基本通知功能外, 還可以傳遞附加信息。1.2 信號(hào)來(lái)源信號(hào)事件的發(fā)生有兩個(gè)來(lái)源: 硬件來(lái)源( 比如我們按下了鍵盤或者其它硬件故障) ; 軟件來(lái)源,最常用發(fā)送信號(hào)的系統(tǒng)函數(shù)是kill, raise, alarm 和 setitimer 以及 sigqueue 函數(shù),軟件來(lái)源還包

46、括一些非法運(yùn)算等操作。2、信號(hào)的種類可以從兩個(gè)不同的分類角度對(duì)信號(hào)進(jìn)行分類: ( 1) 可靠性方面: 可靠信號(hào)與不可靠信號(hào); ( 2)與時(shí)間的關(guān)系上:實(shí)時(shí)信號(hào)與非實(shí)時(shí)信號(hào)。在 Linux 環(huán)境進(jìn)程間通信(一) :管道及有名管道的附 1 中列出了系統(tǒng)所支持的所有信號(hào)。2.1 可靠信號(hào)與不可靠信號(hào)" 不可靠信號(hào)"Linux信號(hào)機(jī)制基本上是從Unix系統(tǒng)中繼承過(guò)來(lái)的。早期Unix系統(tǒng)中的信號(hào)機(jī)制比較簡(jiǎn)單和原始,后來(lái)在實(shí)踐中暴露出一些問(wèn)題,因此,把那些建立在早期機(jī)制上的信號(hào)叫做"不可靠信號(hào)”,信號(hào)值小于 SIGRTMIN(Red hat 7.2中,SIGRTMIN=32,

47、 SIGRTMAX=63的信號(hào)都是不可 靠信號(hào)。這就是"不可靠信號(hào)"的來(lái)源。它的主要問(wèn)題是:? 進(jìn)程每次處理信號(hào)后,就將對(duì)信號(hào)的響應(yīng)設(shè)置為默認(rèn)動(dòng)作。在某些情況下,將導(dǎo)致對(duì)信號(hào)的錯(cuò)誤處理;因此,用戶如果不希望這樣的操作,那么就要在信號(hào)處理函數(shù)結(jié)尾再一次調(diào)用signal。,重新安裝該信號(hào)。? 信號(hào)可能丟失,后面將對(duì)此詳細(xì)闡述。因此,早期unix 下的不可靠信號(hào)主要指的是進(jìn)程可能對(duì)信號(hào)做出錯(cuò)誤的反應(yīng)以及信號(hào)可能丟失。Linux 支持不可靠信號(hào),但是對(duì)不可靠信號(hào)機(jī)制做了改進(jìn):在調(diào)用完信號(hào)處理函數(shù)后,不必重新調(diào)用該信號(hào)的安裝函數(shù)(信號(hào)安裝函數(shù)是在可靠機(jī)制上的實(shí)現(xiàn)) 。因此, Linu

48、x 下的不可 靠信號(hào)問(wèn)題主要指的是信號(hào)可能丟失。" 可靠信號(hào) "隨著時(shí)間的發(fā)展, 實(shí)踐證明了有必要對(duì)信號(hào)的原始機(jī)制加以改進(jìn)和擴(kuò)充。 所以, 后來(lái)出現(xiàn)的各種 Unix 版本分別在這方面進(jìn)行了研究,力圖實(shí)現(xiàn)"可靠信號(hào) " 。由于原來(lái)定義的信號(hào)已有許多應(yīng)用, 不好再做改動(dòng), 最終只好又新增加了一些信號(hào), 并在一開始就把它們定義為可靠信號(hào),這些信號(hào)支持排隊(duì),不會(huì)丟失。同時(shí),信號(hào)的發(fā)送和安裝也出現(xiàn)了新版本:信號(hào)發(fā)送函數(shù)sigqueue()及信號(hào)安裝函數(shù)sigaction()。POSIX.4對(duì)可靠信號(hào)機(jī)制做了標(biāo)準(zhǔn)化。但是,POSIX 只對(duì)可靠信號(hào)機(jī)制應(yīng)具有的功能以及

49、信號(hào)機(jī)制的對(duì)外接口做了標(biāo)準(zhǔn)化, 對(duì)信號(hào)機(jī)制的實(shí)現(xiàn)沒(méi) 有作具體的規(guī)定。信號(hào)值位于SIGRTMIN和SIGRTMAX之間的信號(hào)都是可靠信號(hào),可靠信號(hào)克服了信號(hào)可能丟 失的問(wèn)題。Linux在支持新版本的彳t號(hào)安裝函數(shù)sigation ()以及信號(hào)發(fā)送函數(shù) sigqueue()的同時(shí),仍然支持早期的 signal ()信號(hào)安裝函數(shù),支持信號(hào)發(fā)送函數(shù) kill() 。注:不要有這樣的誤解:由 sigqueue()發(fā)送、sigaction安裝的信號(hào)就是可靠的。事實(shí)上,可靠信號(hào)是指后來(lái)添加的新信號(hào)(信號(hào)值位于SIGRTMIN及SIGRTMAX之間);不可靠信號(hào)是信號(hào)值小于SIGRTMIN的信號(hào)。信號(hào)的可靠與

50、不可靠只與信號(hào)值有關(guān),與信號(hào)的發(fā)送及安裝函數(shù)無(wú)關(guān)。目前l(fā)inux中的signal()是通過(guò)sigation()函數(shù)實(shí)現(xiàn)的,因此,即使通過(guò) signal ()安裝的信號(hào),在信號(hào)處理函數(shù)的結(jié)尾也不必再調(diào)用一次信號(hào)安裝函數(shù)。同時(shí),由signal()安裝的實(shí)時(shí)信號(hào)支持排隊(duì),同樣不會(huì)丟失。對(duì)于目前l(fā)inux的兩個(gè)信號(hào)安裝函數(shù):signal()及sigaction()來(lái)說(shuō),它們都不能把 SIGRTMIN以前 的信號(hào)變成可靠信號(hào) (都不支持排隊(duì), 仍有可能丟失, 仍然是不可靠信號(hào)) , 而且對(duì) SIGRTMIN 以后的信號(hào)都支持排隊(duì)。這兩個(gè)函數(shù)的最大區(qū)別在于,經(jīng)過(guò)sigaction 安裝的信號(hào)都能傳遞信息給

51、信號(hào)處理函數(shù)(對(duì)所有信號(hào)這一點(diǎn)都成立) ,而經(jīng)過(guò) signal 安裝的信號(hào)卻不能向信號(hào) 處理函數(shù)傳遞信息。對(duì)于信號(hào)發(fā)送函數(shù)來(lái)說(shuō)也是一樣的。2.2 實(shí)時(shí)信號(hào)與非實(shí)時(shí)信號(hào)早期 Unix 系統(tǒng)只定義了 32 種信號(hào), Ret hat7.2 支持 64 種信號(hào),編號(hào)0-63(SIGRTMIN=31,SIGRTMAX=63)將來(lái)可能進(jìn)一步增加,這需要得到內(nèi)核的支持。前32種信號(hào)已經(jīng)有了預(yù)定義值,每個(gè)信號(hào)有了確定的用途及含義,并且每種信號(hào)都有各自的缺省動(dòng)作。如按鍵盤的CTRL AC時(shí),會(huì)產(chǎn)生SIGINT信號(hào),對(duì)該信號(hào)的默認(rèn)反應(yīng)就是進(jìn)程終止。后 32個(gè)信號(hào)表示實(shí) 時(shí)信號(hào), 等同于前面闡述的可靠信號(hào)。 這保證

52、了發(fā)送的多個(gè)實(shí)時(shí)信號(hào)都被接收。 實(shí)時(shí)信號(hào)是 POSIX標(biāo)準(zhǔn)的一部分,可用于應(yīng)用進(jìn)程。 非實(shí)時(shí)信號(hào)都不支持排隊(duì),都是不可靠信號(hào);實(shí)時(shí)信號(hào)都支持排隊(duì),都是可靠信號(hào)。3、進(jìn)程對(duì)信號(hào)的響應(yīng)進(jìn)程可以通過(guò)三種方式來(lái)響應(yīng)一個(gè)信號(hào): ( 1 )忽略信號(hào),即對(duì)信號(hào)不做任何處理,其中,有 兩個(gè)信號(hào)不能忽略:SIGKILLM SIGSTOP (2)捕捉信號(hào)。定義信號(hào)處理函數(shù),當(dāng)信號(hào)發(fā)生時(shí),執(zhí)行相應(yīng)的處理函數(shù);( 3 )執(zhí)行缺省操作,Linux 對(duì)每種信號(hào)都規(guī)定了默認(rèn)操作,詳細(xì)情況請(qǐng)參考 2 以及其它資料。注意,進(jìn)程對(duì)實(shí)時(shí)信號(hào)的缺省反應(yīng)是進(jìn)程終止。Linux究竟采用上述三種方式的哪一個(gè)來(lái)響應(yīng)信號(hào),取決于傳遞給相應(yīng)AP

53、I函數(shù)的參數(shù)。4、信號(hào)的發(fā)送發(fā)送信號(hào)的主要函數(shù)有:kill()、raise。、 sigqueue()、alarm。、setitimer()以及 abort()。1、kill()#include <sys/types.h>#include <signal.h> int kill(pid_t pid,int signo)參數(shù)pid的值信號(hào)的接收進(jìn)程pid>0進(jìn)程ID為pid的進(jìn)程pid=0同一個(gè)進(jìn)程組的進(jìn)程pid<0 pid!=-1進(jìn)程組ID為-pid的所有進(jìn)程pid=-1除發(fā)送進(jìn)程自身外,所有進(jìn)程ID大于1的進(jìn)程Sinno是信號(hào)值,當(dāng)為0時(shí)(即空信號(hào)),實(shí)際不

54、發(fā)送任何信號(hào), 但照常進(jìn)行錯(cuò)誤檢查, 因此, 可用于檢查目標(biāo)進(jìn)程是否存在, 以及當(dāng)前進(jìn)程是否具有向目標(biāo)發(fā)送信號(hào)的權(quán)限(root權(quán)限的進(jìn)程可以向任何進(jìn)程發(fā)送信號(hào),非 root權(quán)限的進(jìn)程只能向?qū)儆谕粋€(gè) session或者同一個(gè)用 戶的進(jìn)程發(fā)送信號(hào))。Kill()最常用于pid>0時(shí)的信號(hào)發(fā)送,調(diào)用成功返回0;否則,返回-1。注:對(duì)于pid<0時(shí)的情況,對(duì)于哪些進(jìn)程將接受信號(hào),各種版本說(shuō)法不一,其實(shí)很簡(jiǎn)單,參閱內(nèi)核源碼 kernal/signal.c即可,上表中的規(guī)則是參考red hat 7.2。2、raise ()#include <signal.h>int raise(

55、int signo)0;否則,返回-1。向進(jìn)程本身發(fā)送信號(hào),參數(shù)為即將發(fā)送的信號(hào)值。調(diào)用成功返回3、sigqueue ()#include <sys/types.h>#include <signal.h>int sigqueue(pid_t pid, int sig, const union sigval val)調(diào)用成功返回0;否則,返回-1。sigqueue()是比較新的發(fā)送信號(hào)系統(tǒng)調(diào)用,主要是針對(duì)實(shí)時(shí)信號(hào)提出的(當(dāng)然也支持前32種),支持信號(hào)帶有參數(shù),與函數(shù)sigaction()配合使用。sigqueue的第一個(gè)參數(shù)是指定接收信號(hào)的進(jìn)程ID,第二個(gè)參數(shù)確定即將發(fā)送的信號(hào),第三個(gè)參數(shù)是一個(gè)聯(lián)合數(shù)據(jù)結(jié)構(gòu)union sigval,指定了信號(hào)傳遞的參數(shù),即通常所說(shuō)的4字節(jié)值。typedef union sigval int sival_int; void *sival_ptr;sigval_t;sigqueue()比kill()傳遞了更多的附加信息,但sigqueue()只能向一個(gè)進(jìn)程發(fā)送信號(hào),而不能發(fā)送信號(hào)給一個(gè)進(jìn)程組。如果 signo

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論