![嵌入式軟件開發(fā)技術(shù):第4章 嵌入式Linux進(jìn)程間通信_(tái)第1頁(yè)](http://file4.renrendoc.com/view/8c6a523c9258a76a41a27541cf231287/8c6a523c9258a76a41a27541cf2312871.gif)
![嵌入式軟件開發(fā)技術(shù):第4章 嵌入式Linux進(jìn)程間通信_(tái)第2頁(yè)](http://file4.renrendoc.com/view/8c6a523c9258a76a41a27541cf231287/8c6a523c9258a76a41a27541cf2312872.gif)
![嵌入式軟件開發(fā)技術(shù):第4章 嵌入式Linux進(jìn)程間通信_(tái)第3頁(yè)](http://file4.renrendoc.com/view/8c6a523c9258a76a41a27541cf231287/8c6a523c9258a76a41a27541cf2312873.gif)
![嵌入式軟件開發(fā)技術(shù):第4章 嵌入式Linux進(jìn)程間通信_(tái)第4頁(yè)](http://file4.renrendoc.com/view/8c6a523c9258a76a41a27541cf231287/8c6a523c9258a76a41a27541cf2312874.gif)
![嵌入式軟件開發(fā)技術(shù):第4章 嵌入式Linux進(jìn)程間通信_(tái)第5頁(yè)](http://file4.renrendoc.com/view/8c6a523c9258a76a41a27541cf231287/8c6a523c9258a76a41a27541cf2312875.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1
4.1Linux下進(jìn)程間通信概述4.2管道通信4.3信號(hào)通信4.4信號(hào)量4.5共享內(nèi)存4.6消息隊(duì)列第4章嵌入式Linux進(jìn)程間通信2
繼承Unix平臺(tái)上進(jìn)程通信手段集合SystemVIPC(貝爾實(shí)驗(yàn)室)和socket的進(jìn)程間通信機(jī)制(BSD)的優(yōu)勢(shì)4.1Linux下進(jìn)程間通信概述管道、FIFO、信號(hào)SystemV消息隊(duì)列、信號(hào)量、共享內(nèi)存Posix消息隊(duì)列、信號(hào)量、共享內(nèi)存3
Linux中常用的進(jìn)程間通信機(jī)制管道(Pipe)及有名管道(NamedPipe)信號(hào)(Signal):
在軟件層次上對(duì)中斷機(jī)制的模擬,用于通知進(jìn)程有某事件發(fā)生。消息隊(duì)列(MessageQueue):消息隊(duì)列是消息的鏈接表,包括Posix消息隊(duì)列SystemV消息隊(duì)列。它克服了前兩種通信方式中信息量有限的缺點(diǎn),具有寫權(quán)限的進(jìn)程可以按照一定的規(guī)則向消息隊(duì)列中添加新消息;對(duì)消息隊(duì)列有讀權(quán)限的進(jìn)程則可以從消息隊(duì)列中讀取消息。4.1Linux下進(jìn)程間通信概述4
Linux中常用的進(jìn)程間通信機(jī)制共享內(nèi)存(SharedMemory):它使得多個(gè)進(jìn)程可以訪問同一塊內(nèi)存空間,不同進(jìn)程可以及時(shí)看到對(duì)方進(jìn)程中對(duì)共享內(nèi)存中數(shù)據(jù)的更新。這種通信方式需要依靠某種同步機(jī)制,如互斥鎖和信號(hào)量等。信號(hào)量(Semaphore):主要作為進(jìn)程之間以及同一進(jìn)程的不同線程之間的同步和互斥手段。套接字(Socket):可用于網(wǎng)絡(luò)中不同機(jī)器之間的進(jìn)程間通信4.1Linux下進(jìn)程間通信概述5
4.2.1管道簡(jiǎn)介無名管道它只能用于具有親緣關(guān)系的進(jìn)程之間的通信(也就是父子進(jìn)程或者兄弟進(jìn)程之間)。它是一個(gè)半雙工的通信模式,具有固定的讀端和寫端。管道也可以看成是一種特殊的文件,對(duì)于它的讀寫也可以使用普通的read()、write()等函數(shù)。但是它不是普通的文件,并不屬于其他任何文件系統(tǒng),并且只存在于內(nèi)存中.4.2管道通信6
4.2.1管道簡(jiǎn)介有名管道(FIFO)它可以使互不相關(guān)的兩個(gè)進(jìn)程實(shí)現(xiàn)彼此通信。該管道可以通過路徑名來指出,并且在文件系統(tǒng)中是可見的。在建立了管道之后,兩個(gè)進(jìn)程就可以把它當(dāng)作普通文件一樣進(jìn)行讀寫操作,使用非常方便。FIFO嚴(yán)格地遵循先進(jìn)先出規(guī)則,對(duì)管道及FIFO的讀總是從開始處返回?cái)?shù)據(jù),對(duì)它們的寫則把數(shù)據(jù)添加到末尾,它們不支持如lseek()等文件定位操作。4.2管道通信7
4.2.2無名管道系統(tǒng)調(diào)用管道創(chuàng)建和關(guān)閉管道是基于文件描述符的通信方式,當(dāng)一個(gè)管道建立時(shí),它會(huì)創(chuàng)建兩個(gè)文件描述符fds[0]和fds[1],其中fds[0]固定用于讀管道,而fd[1]固定用于寫管道,這樣就構(gòu)成了一個(gè)半雙工的通道。4.2管道通信8
4.2.2無名管道系統(tǒng)調(diào)用pipe()創(chuàng)建管道可以通過調(diào)用pipe()來實(shí)現(xiàn).pipe()語(yǔ)法:4.2管道通信所需頭文件#include<unistd.h>函數(shù)原型intpipe(intfd[2])函數(shù)傳入值管道的兩個(gè)文件描述符返回值成功:0出錯(cuò):19
4.2.2無名管道系統(tǒng)調(diào)用管道讀寫:通常先創(chuàng)建一個(gè)管道,再調(diào)用fork()函數(shù)創(chuàng)建一子進(jìn)程,該子進(jìn)程繼承父進(jìn)程創(chuàng)建的管道。4.2管道通信10
4.2.2無名管道系統(tǒng)調(diào)用管道讀寫:為了實(shí)現(xiàn)父子進(jìn)程之間的讀寫,只需把無關(guān)的讀端或?qū)懚说奈募枋龇P(guān)閉即可,如下圖建立的“子進(jìn)程寫入父進(jìn)程讀取的通道。4.2管道通信11
4.2.2無名管道系統(tǒng)調(diào)用管道讀寫注意點(diǎn):只有在管道的讀端存在時(shí),向管道寫入數(shù)據(jù)才有意義。否則,向管道寫入數(shù)據(jù)的進(jìn)程將收到內(nèi)核傳來的SIGPIPE信號(hào)(通常為Brokenpipe錯(cuò)誤)。向管道寫入數(shù)據(jù)時(shí),Linux將不保證寫入的原子性,管道緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程就會(huì)試圖向管道寫入數(shù)據(jù)。如果讀進(jìn)程不讀取管道緩沖區(qū)中的數(shù)據(jù),那么寫操作將會(huì)一直阻塞。父子進(jìn)程在運(yùn)行時(shí),它們的先后次序并不能保證,因此,在為了保證父子進(jìn)程已經(jīng)關(guān)閉了相應(yīng)的文件描述符,可在兩個(gè)進(jìn)程中調(diào)用sleep()函數(shù),當(dāng)然這種調(diào)用不是很好的解決方法,在后面學(xué)到進(jìn)程之間的同步與互斥機(jī)制之后,請(qǐng)讀者自行修改本小節(jié)的實(shí)例程序。4.2管道通信12
4.2.2無名管道系統(tǒng)調(diào)用管道使用實(shí)例:intmain(){ pid_tpid; intpipe_fd[2]; charbuf[MAX_DATA_LEN]; constchardata[]="PipeTestProgram"; intreal_read,real_write; memset((void*)buf,0,sizeof(buf)); if(pipe(pipe_fd)<0)/*創(chuàng)建管道*/ { printf("pipecreateerror\n"); exit(1); }4.2管道通信13
4.2.2無名管道系統(tǒng)調(diào)用管道使用實(shí)例:if((pid=fork())==0)/*創(chuàng)建一子進(jìn)程*/ { close(pipe_fd[1]); sleep(DELAY_TIME*3); /*子進(jìn)程讀取管道內(nèi)容*/ if((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) { printf("%dbytesreadfromthepipeis'%s'\n",real_read,buf); } close(pipe_fd[0]);/*關(guān)閉子進(jìn)程讀描述符*/ exit(0); }4.2管道通信14
4.2.2無名管道系統(tǒng)調(diào)用管道使用實(shí)例: elseif(pid>0) { close(pipe_fd[0]); sleep(DELAY_TIME); if((real_write=write(pipe_fd[1],data,strlen(data)))!=-1) { printf("Parentwrote%dbytes:'%s'\n",real_write,data); } close(pipe_fd[1]);/*關(guān)閉父進(jìn)程寫描述符*/ waitpid(pid,NULL,0);/*收集子進(jìn)程退出信息*/ exit(0); }}4.2管道通信15
4.2.3有名管道(FIFO)
有名管道又稱為命名管道,可以使不相關(guān)的進(jìn)程實(shí)現(xiàn)互相通信。FIFO和一般管道的不同主要體現(xiàn)在:命名管道在文件系統(tǒng)中作為一個(gè)特殊的設(shè)備文件存在。不同祖先的進(jìn)程之間可以通過管道共享數(shù)據(jù)。當(dāng)共享管道的進(jìn)程執(zhí)行完所有的I/O操作以后,命名管道繼續(xù)保存在文件系統(tǒng)中以便以后使用。4.2管道通信16
4.2.3有名管道(FIFO)通過mkfifo()創(chuàng)建有名管道
mkfifio()函數(shù)基本語(yǔ)法:函數(shù)所需頭文件:#include<sys/types.h> #include<sys/stat.h>函數(shù)原型:intmkfifo(constchar*pathname, mode_tmode);函數(shù)輸入值:pathname為要?jiǎng)?chuàng)建的管道名;第二個(gè)參數(shù)mode指明讀寫權(quán)限與方式,可以是O_RDONLY(只讀管道)、O_WRONLY(只寫管道)、O_RDWR(讀寫管道)、O_NONBLOCK(非阻塞方式)、O_CREAT(管道文件不存在,就創(chuàng)建一個(gè)新的)、O_EXCL(測(cè)試文件是否存在)。函數(shù)返回值:若成功則為0,若出錯(cuò)返回-14.2管道通信17
4.2.3有名管道(FIFO)FIFO讀寫一旦已經(jīng)用mkfifo創(chuàng)建了一個(gè)FIFO,就可用open打開它。一般的文件I/O函數(shù)(close,read,write,unlink等)都可用于FIFO。
4.2管道通信18
4.2.3有名管道(FIFO)FIFO讀寫對(duì)于讀進(jìn)程若該管道是阻塞打開,且當(dāng)前FIFO內(nèi)沒有數(shù)據(jù),則對(duì)讀進(jìn)程而言將一直阻塞到有數(shù)據(jù)寫入。若該管道是非阻塞打開,則不論FIFO內(nèi)是否有數(shù)據(jù),讀進(jìn)程都會(huì)立即執(zhí)行讀操作。即如果FIFO內(nèi)沒有數(shù)據(jù),則讀函數(shù)將立刻返回0。對(duì)于寫進(jìn)程若該管道是阻塞打開,則寫操作將一直阻塞到數(shù)據(jù)可以被寫入。若該管道是非阻塞打開而不能寫入全部數(shù)據(jù),則寫操作進(jìn)行部分寫入或者調(diào)用失敗。
4.2管道通信19
4.2.3有名管道(FIFO)FIFO使用實(shí)例采用阻塞式讀寫管道模式。在讀管道的程序里創(chuàng)建管道,要寫入的內(nèi)容通過寫管道程序的main函數(shù)的參數(shù)由用戶輸入;讀管道的程序讀出用戶寫入到管道的內(nèi)容。
4.2管道通信20
4.2.3有名管道(FIFO)FIFO使用實(shí)例——讀管道
4.2管道通信/*fifo_read.c*/#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<fcntl.h>#include<stdio.h>#include<stdlib.h>#include<limits.h>#defineMYFIFO "/tmp/myfifo" /*有名管道文件名*/#defineMAX_BUFFER_SIZE PIPE_BUF /*定義在limits.h中*/21
4.2.3有名管道(FIFO)FIFO使用實(shí)例——讀管道
4.2管道通信intmain(){ charbuff[MAX_BUFFER_SIZE]; intfd; intnread; if(access(MYFIFO,F_OK)==-1) { if((mkfifo(MYFIFO,0666)<0)&&(errno!=EEXIST)) { printf("Cannotcreatefifofile\n"); exit(1); } }22
4.2.3有名管道(FIFO)FIFO使用實(shí)例——讀管道
4.2管道通信 fd=open(MYFIFO,O_RDONLY); if(fd==-1) { printf("Openfifofileerror\n"); exit(1); } while(1) { memset(buff,0,sizeof(buff)); if((nread=read(fd,buff,MAX_BUFFER_SIZE))>0) { printf("Read'%s'fromFIFO\n",buff); } } close(fd); exit(0);}23
4.2.3有名管道(FIFO)FIFO使用實(shí)例——寫管道
4.2管道通信intmain(intargc,char*argv[]) { intfd; charbuff[MAX_BUFFER_SIZE]; intnwrite; if(argc<=1) { printf("Usage:./fifo_writestring\n"); exit(1); } sscanf(argv[1],"%s",buff);24
4.2.3有名管道(FIFO)FIFO使用實(shí)例——寫管道4.2管道通信 fd=open(MYFIFO,O_WRONLY); if(fd==-1) { printf("Openfifofileerror\n"); exit(1); } /*向管道中寫入字符串*/ if((nwrite=write(fd,buff,MAX_BUFFER_SIZE))>0) { printf("Write'%s'toFIFO\n",buff); } close(fd); return0;}25
4.2.4標(biāo)準(zhǔn)流管道與Linux的文件操作中有基于文件流的標(biāo)準(zhǔn)I/O操作一樣,管道的操作也支持基于文件流的模式。這種基于文件流的管道主要是用來創(chuàng)建一個(gè)連接到另一個(gè)進(jìn)程的管道,這里的“另一個(gè)進(jìn)程”也就是一個(gè)可以進(jìn)行一定操作的可執(zhí)行文件。4.2管道通信26
4.2.4標(biāo)準(zhǔn)流管道標(biāo)準(zhǔn)流管道函數(shù)說明標(biāo)準(zhǔn)流管道將一系列的創(chuàng)建過程合并到一個(gè)函數(shù)popen()中完成,包括以下幾步:創(chuàng)建一個(gè)管道;fork()一個(gè)子進(jìn)程;在父子進(jìn)程中關(guān)閉不需要的文件描述符;執(zhí)行exec函數(shù)族調(diào)用;執(zhí)行函數(shù)中所指定的命令。4.2管道通信27
4.2.4標(biāo)準(zhǔn)流管道popen():創(chuàng)建標(biāo)準(zhǔn)流管道函數(shù)格式:4.2管道通信28
4.2.4標(biāo)準(zhǔn)流管道pclose():關(guān)閉標(biāo)準(zhǔn)流管道函數(shù)格式:4.2管道通信29
4.2.3標(biāo)準(zhǔn)流管道使用實(shí)例:#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<fcntl.h>#defineBUFSIZE1024intmain(){ FILE*fp; char*cmd="ps-ef"; charbuf[BUFSIZE];4.2管道通信30
4.2.3標(biāo)準(zhǔn)流管道使用實(shí)例: if((fp=popen(cmd,"r"))==NULL) { printf("Popenerror\n"); exit(1); } while((fgets(buf,BUFSIZE,fp))!=NULL) { printf("%s",buf); } pclose(fp); exit(0);}4.2管道通信31
4.2.3標(biāo)準(zhǔn)流管道類型為“w”,文件指針連接到command的標(biāo)準(zhǔn)輸入?4.2管道通信32
4.3.1信號(hào)概述信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,是一種異步通信方式,一個(gè)進(jìn)程不必通過任何操作來等待信號(hào)的到達(dá)。信號(hào)可以直接進(jìn)行用戶空間進(jìn)程和內(nèi)核進(jìn)程之間的交互,內(nèi)核進(jìn)程也可以利用它來通知用戶空間進(jìn)程發(fā)生了哪些系統(tǒng)事件。它可以在任何時(shí)候發(fā)給某一進(jìn)程,而無需知道該進(jìn)程的狀態(tài)。如果該進(jìn)程當(dāng)前并未處于執(zhí)行態(tài),則該信號(hào)就由內(nèi)核保存起來,直到該進(jìn)程恢復(fù)執(zhí)行再傳遞給它;如果一個(gè)信號(hào)被進(jìn)程設(shè)置為阻塞,則該信號(hào)的傳遞被延遲,直到其阻塞被取消時(shí)才被傳遞給進(jìn)程
4.3信號(hào)通信33
4.3.1信號(hào)概述信號(hào)事件的發(fā)生有硬件來源和軟件來源,最常用的發(fā)送信號(hào)的函數(shù)有kill()、raise()、alarm()、setitimer()和sigqueue()等。進(jìn)程響應(yīng)信號(hào)的方式執(zhí)行缺省操作,Linux對(duì)每種信號(hào)都規(guī)定了默認(rèn)操作。忽略信號(hào),即對(duì)信號(hào)不做任何處理,其中,有兩個(gè)信號(hào)不能忽略:SIGKILL及SIGSTOP。捕捉信號(hào),定義信號(hào)處理函數(shù),當(dāng)信號(hào)發(fā)生時(shí),執(zhí)行相應(yīng)的處理函數(shù)。
4.3信號(hào)通信34
4.3.1信號(hào)概述常見信號(hào)及其缺省操作4.3信號(hào)通信35
4.3.1信號(hào)概述信號(hào)的處理包括信號(hào)的發(fā)送、捕獲以及信號(hào)的安裝:發(fā)送信號(hào):kill()、raise()、alarm()捕獲信號(hào):pause()處理信號(hào):signal()、sigaction()4.3信號(hào)通信36
4.3.2信號(hào)發(fā)送和捕捉(1)信號(hào)發(fā)送:kill和raise函數(shù)系統(tǒng)命令kill只是kill函數(shù)的一個(gè)用戶接口。而實(shí)際的kill()函數(shù)不僅可以中止進(jìn)程,也可以向進(jìn)程發(fā)送其他信號(hào)。與kill函數(shù)不同的是,raise()函數(shù)允許進(jìn)程向自身發(fā)送信號(hào)。函數(shù)的基本語(yǔ)法:所需頭文件:#include<sys/types.h>#include<signal.h>函數(shù)原型:intkill(pid_tpid,intsigno);
intraise(intsigno);4.3信號(hào)通信37
4.3.2信號(hào)發(fā)送和捕捉(1)信號(hào)發(fā)送:kill和raise函數(shù)兩個(gè)函數(shù)返回值含義一致:若成功則為0,若出錯(cuò)則為-1函數(shù)的輸入?yún)?shù):signo為發(fā)送的信號(hào)。kill的另一個(gè)參數(shù)pid有四種情況:①pid>0將信號(hào)發(fā)送給進(jìn)程ID為pid的進(jìn)程。②pid==0將信號(hào)發(fā)送給所有和pid進(jìn)程在同一個(gè)進(jìn)程組的進(jìn)程。③pid==-1將信號(hào)發(fā)給所有的進(jìn)程表中的進(jìn)程,進(jìn)程號(hào)最大的進(jìn)程除外。④pid<0將信號(hào)發(fā)給進(jìn)程組號(hào)為pid絕對(duì)值的所有進(jìn)程4.3信號(hào)通信38
4.3.2信號(hào)發(fā)送和捕捉(1)信號(hào)發(fā)送實(shí)例程序流程使用fork()創(chuàng)建一個(gè)子進(jìn)程;在子進(jìn)程中調(diào)用raise()函數(shù)向自身發(fā)送SIGSTOP信號(hào),使子進(jìn)程暫停;在父進(jìn)程中調(diào)用kill()向子進(jìn)程發(fā)送SIGKILL信號(hào),結(jié)束子進(jìn)程。結(jié)束父進(jìn)程。4.3信號(hào)通信39
4.3.2信號(hào)發(fā)送和捕捉(1)信號(hào)發(fā)送實(shí)例intmain(){ pid_tpid; intret; /*創(chuàng)建一子進(jìn)程*/ if((pid=fork())<0) { printf("Forkerror\n"); exit(1); } if(pid==0) { printf("Child(pid:%d)iswaitingforanysignal\n",getpid()); raise(SIGSTOP); exit(0); }4.3信號(hào)通信40
4.3.2信號(hào)發(fā)送和捕捉(1)信號(hào)發(fā)送實(shí)例 else { /*在父進(jìn)程中收集子進(jìn)程發(fā)出的信號(hào),并調(diào)用kill()函數(shù)進(jìn)行相應(yīng)的操作*/ if((waitpid(pid,NULL,WNOHANG))==0) { if((ret==kill(pid,SIGKILL))==0) printf("Parentkill%d\n",pid); } waitpid(pid,NULL,0); exit(0); }}4.3信號(hào)通信41
4.3.2信號(hào)發(fā)送和捕捉信號(hào)捕捉:alarm()、pause()alarm()也稱為鬧鐘函數(shù),它可以在進(jìn)程中設(shè)置一個(gè)定時(shí)器,當(dāng)定時(shí)器指定的時(shí)間到時(shí),它就向進(jìn)程發(fā)送SIGALARM信號(hào)。SIGALRM信號(hào)默認(rèn)動(dòng)作是終止該進(jìn)程。與之對(duì)應(yīng),pause函數(shù)是使調(diào)用進(jìn)程掛起直至捕捉到一個(gè)信號(hào),這個(gè)信號(hào)通常用來判斷信號(hào)是否已到。4.3信號(hào)通信42
4.3.2信號(hào)發(fā)送和捕捉信號(hào)捕捉:alarm()、pause()alarm函數(shù)的基本語(yǔ)法:所需頭文件:#include<unistd.h>函數(shù)原型:unsignedintalarm(unsignedintseconds);函數(shù)的傳入?yún)?shù)seconds的值是秒數(shù),經(jīng)過了指定的seconds秒后產(chǎn)生信號(hào)SIGALRM。函數(shù)返回值:0或以前設(shè)置的鬧鐘時(shí)間的余留秒數(shù)。每個(gè)進(jìn)程只能有一個(gè)鬧鐘時(shí)間。如果在調(diào)用alarm時(shí),已為該進(jìn)程設(shè)置過鬧鐘時(shí)間,則該鬧鐘的余留值作為本次函數(shù)調(diào)用的返回值,并為鬧鐘設(shè)置新值。如果函數(shù)調(diào)用時(shí)參數(shù)seconds值為0,則返回剩余時(shí)間值并取消鬧鐘。4.3信號(hào)通信43
4.3.2信號(hào)發(fā)送和捕捉信號(hào)捕捉:alarm()、pause()pause函數(shù)的基本語(yǔ)法:所需頭文件:#include<unistd.h>函數(shù)原型:intpause(void);函數(shù)返回值:-1,并將errno設(shè)置為EINTR。4.3信號(hào)通信44
4.3.2信號(hào)發(fā)送和捕捉信號(hào)捕捉:alarm()、pause()#include<unistd.h>#include<stdio.h>#include<stdlib.h>intmain(){ /*調(diào)用alarm定時(shí)器函數(shù)*/ intret=alarm(5); pause(); printf("Ihavebeenwakenup.\n"); return0;}4.3信號(hào)通信45
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:signal、sigactionsignal()處理信號(hào)時(shí),只需要指出要處理的信號(hào)和處理函數(shù)即可。它主要是用于前32種非實(shí)時(shí)信號(hào)的處理,不支持信號(hào)傳遞信息。4.3信號(hào)通信46
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:signal函數(shù)的使用示例#include<signal.h>#include<stdio.h>#include<stdlib.h>voidmy_func(intsign_no){ if(sign_no==SIGINT) { printf("IhavegetSIGINT\n"); } elseif(sign_no==SIGQUIT) { printf("IhavegetSIGQUIT\n"); }}4.3信號(hào)通信47
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:signal、sigactionintmain(){ printf("WaitingforsignalSIGINTorSIGQUIT...\n"); /*如果收到相應(yīng)的信號(hào),并跳轉(zhuǎn)到信號(hào)處理函數(shù)處*/ signal(SIGINT,my_func); signal(SIGQUIT,my_func); pause(); exit(0);}4.3信號(hào)通信48
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:sigactionsigaction()函數(shù)相對(duì)于signal()更加健壯。4.3信號(hào)通信49
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:sigactionsigaction()函數(shù)中第2個(gè)和第3個(gè)參數(shù)用到的sigaction結(jié)構(gòu)
structsigaction{ void(*sa_handler)(intsigno); sigset_tsa_mask; intsa_flags; void(*sa_restore)(void);}4.3信號(hào)通信50
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:sigactionsa_handler是一個(gè)函數(shù)指針,指定信號(hào)處理函數(shù),這里除可以是用戶自定義的處理函數(shù)外,還可以為SIG_DFL(采用缺省的處理方式)或SIG_IGN(忽略信號(hào))。它的處理函數(shù)只有一個(gè)參數(shù),即信號(hào)值。sa_mask是一個(gè)信號(hào)集,它可以指定在信號(hào)處理程序執(zhí)行過程中哪些信號(hào)應(yīng)當(dāng)被屏蔽,在調(diào)用信號(hào)捕獲函數(shù)之前,該信號(hào)集要加入到信號(hào)的信號(hào)屏蔽字中。sa_flags中包含了許多標(biāo)志位,是對(duì)信號(hào)進(jìn)行處理的各個(gè)選擇項(xiàng)sa_restore:Thesa_restorerelementisobsoleteandshouldnotbeused.POSIXdoesnotspecifyasa_restorerelement.4.3信號(hào)通信51
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:sigaction示例intmain(){ structsigactionaction; printf("WaitingforsignalSIGINTorSIGQUIT...\n"); action.sa_handler=my_func;
sigemptyset(&action.sa_mask); action.sa_flags=0; sigaction(SIGINT,&action,0); sigaction(SIGQUIT,&action,0); pause(); return0;}4.3信號(hào)通信52
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:使用信號(hào)集函數(shù)組處理信號(hào)時(shí)一般的操作流程:信號(hào)的操作流程也說明了信號(hào)集函數(shù)組中函數(shù)調(diào)用的先后次序。信號(hào)集函數(shù)組包含幾大模塊:創(chuàng)建信號(hào)集合、注冊(cè)信號(hào)處理函數(shù)、檢測(cè)信號(hào)集。4.3信號(hào)通信53
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:使用信號(hào)集函數(shù)組創(chuàng)建信號(hào)集合用于創(chuàng)建程序用到的信號(hào),它的函數(shù)主要包含以下五個(gè):sigemptyset:初始化信號(hào)集合為空;sigfillset:初始化信號(hào)集合為所有的信號(hào)集合;sigaddset:將指定信號(hào)添加到現(xiàn)存集中;sigdelset:從信號(hào)集中刪除指定信號(hào);sigismember:查詢指定信號(hào)是否在信號(hào)集中。4.3信號(hào)通信54
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:使用信號(hào)集函數(shù)組上述創(chuàng)建信號(hào)集函數(shù)語(yǔ)法格式分別為:所需包含頭文件:#include<signal.h>函數(shù)原型:intsigemptyset(sigset_t*set);intsigfillset(sigset_t*set);intsigaddset(sigset_t*set,intsigno);intsigdelset(sigset_t*set,intsigno);以上四個(gè)函數(shù)返回值:若成功則為0,若出錯(cuò)則為-1
intsigismember(constsigset_t*set,intsigno);sigismember函數(shù)返回值:若真則為1,若假則為0;函數(shù)輸入?yún)?shù):set為信號(hào)集;signo為指定信號(hào)。4.3信號(hào)通信55
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:使用信號(hào)集函數(shù)組登記信號(hào)集函數(shù)主要用于決定進(jìn)程如何處理信號(hào)。一個(gè)進(jìn)程的信號(hào)屏蔽字可以規(guī)定當(dāng)前阻塞而不能遞送給該進(jìn)程的信號(hào)集。這里首先使用sigprocmask函數(shù)判斷檢測(cè)或更改進(jìn)程的信號(hào)屏蔽字,然后使用sigaction函數(shù)改變進(jìn)程接受到特定信號(hào)之后的行為。sigprocmask函數(shù)的語(yǔ)法格式如下:函數(shù)所需頭文件:#include<signal.h>函數(shù)原型:intsigprocmask(inthow,constsigset_t*set,sigset_t*oldset);函數(shù)返回值:若成功則為0,若出錯(cuò)則為-14.3信號(hào)通信56
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:使用信號(hào)集函數(shù)組函數(shù)輸入?yún)?shù)how參數(shù)決定函數(shù)的操作方式:SIG_BLOCK:該進(jìn)程新的信號(hào)屏蔽字是其當(dāng)前信號(hào)屏蔽字和set指向信號(hào)集的并集。set參數(shù)包含了我們希望阻塞的附加信號(hào),也就是將參數(shù)set指定的信號(hào)集設(shè)為阻塞狀態(tài)。SIG_UNBLOCK:從當(dāng)前的阻塞集合之中刪除一個(gè)信號(hào)集合SIG_SETMASK:該進(jìn)程新的信號(hào)屏蔽設(shè)為set指向的值。如果set是個(gè)空指針,則不改變?cè)撨M(jìn)程的信號(hào)屏蔽字,how的值也無意義。4.3信號(hào)通信57
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:使用信號(hào)集函數(shù)組定義信號(hào)處理函數(shù)與sigprocmask函數(shù)相對(duì)應(yīng),sigaction函數(shù)的功能是檢查或修改(或兩者)與進(jìn)程收到指定信號(hào)之后相關(guān)聯(lián)的處理動(dòng)作。sigaction函數(shù)的基本語(yǔ)法如下:函數(shù)所需的頭文件:#include<signal.h>函數(shù)原型:intsigaction(intsigno,conststructsigaction*act,structsigaction*oldact);函數(shù)返回值:若成功則為0,若出錯(cuò)則為-14.3信號(hào)通信58
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:使用信號(hào)集函數(shù)組檢測(cè)信號(hào)集是信號(hào)處理的后續(xù)步驟,但不是必須的。sigpending函數(shù)運(yùn)行進(jìn)程檢測(cè)“未決“信號(hào)(進(jìn)程不清楚他的存在),并進(jìn)一步?jīng)Q定對(duì)他們做何處理。sigpending函數(shù)的基本語(yǔ)法如下:函數(shù)所需頭文件:#include<signal.h>函數(shù)原型:intsigpending(sigset_t*set);函數(shù)的傳入?yún)?shù):set為要檢測(cè)的信號(hào)集。函數(shù)返回值:若成功則為0,若出錯(cuò)則為-1該函數(shù)將被擱置的信號(hào)集由set指針返回。4.3信號(hào)通信59
4.3.2信號(hào)發(fā)送和捕捉信號(hào)的處理:信號(hào)集函數(shù)組使用示例
該示例首先把SIGQUIT、SIGINT兩個(gè)信號(hào)加入信號(hào)集,然后將該信號(hào)集設(shè)為阻塞狀態(tài),并進(jìn)入用戶輸入狀態(tài)。用戶只需按任意鍵,就可以立刻將信號(hào)集合設(shè)置為非阻塞狀態(tài),再對(duì)兩個(gè)信號(hào)分別操作,其中SIGQUIT執(zhí)行默認(rèn)操作,而SIGINT執(zhí)行用戶自定義函數(shù)的操作。4.3信號(hào)通信60
4.4.1信號(hào)量概述信號(hào)量是用來解決進(jìn)程之間的同步與互斥問題的一種進(jìn)程之間通信機(jī)制,包括一個(gè)稱為信號(hào)量的變量和在該信號(hào)量下等待資源的進(jìn)程等待隊(duì)列,以及對(duì)信號(hào)量進(jìn)行的兩個(gè)原子操作(PV操作)。其中信號(hào)量對(duì)應(yīng)于某一種資源,取一個(gè)非負(fù)的整型值。信號(hào)量值指的是當(dāng)前可用的該資源的數(shù)量,若它等于0則意味著目前沒有可用的資源。4.4信號(hào)量61
4.4.1信號(hào)量概述PV原子操作的具體定義為:P操作:如果有可用的資源(信號(hào)量值>0),則占用一個(gè)資源(給信號(hào)量值減去一,進(jìn)入臨界區(qū)代碼);如果沒有可用的資源(信號(hào)量值等于0),則被阻塞,直到系統(tǒng)將資源分配給該進(jìn)程(進(jìn)入等待隊(duì)列,一直等到資源輪到該進(jìn)程)。V操作:如果在該信號(hào)量的等待隊(duì)列中有進(jìn)程在等待資源,則喚醒一個(gè)阻塞進(jìn)程。如果沒有進(jìn)程等待它,則釋放一個(gè)資源(給信號(hào)量值加一)。4.4信號(hào)量62
4.4.2信號(hào)量編程Linux系統(tǒng)中,使用信號(hào)量通常分為以下的步驟:第一步:創(chuàng)建信號(hào)量或獲得在系統(tǒng)已存在的信號(hào)量,此時(shí)需要調(diào)用semget()函數(shù)。不同進(jìn)程通過使用同一個(gè)信號(hào)量鍵值來獲得同一個(gè)信號(hào)量。第二步:初始化信號(hào)量,此時(shí)使用semctl()函數(shù)的SETVAL操作。當(dāng)使用二維信號(hào)量時(shí),通常將信號(hào)量初始化為1。第三步:進(jìn)行信號(hào)量的PV操作,此時(shí)調(diào)用semop()函數(shù)。這一步是實(shí)現(xiàn)進(jìn)程之間的同步和互斥的核心工作部分。第四步:如果不需要信號(hào)量,則從系統(tǒng)中刪除它,此時(shí)使用semctl()函數(shù)的IPC_RMID操作。此時(shí)需要注意,在程序中不應(yīng)該出現(xiàn)對(duì)已經(jīng)被刪除的信號(hào)量的操作。4.4信號(hào)量63
4.4.2信號(hào)量編程semget()函數(shù)語(yǔ)法:4.4信號(hào)量64
4.4.2信號(hào)量編程semctl()函數(shù)語(yǔ)法:4.4信號(hào)量65
4.4.2信號(hào)量編程semop()函數(shù)語(yǔ)法:4.4信號(hào)量66
4.4.2信號(hào)量編程信號(hào)量相關(guān)函數(shù)的封裝4.4信號(hào)量/*信號(hào)量初始化(賦值)函數(shù)*/intinit_sem(intsem_id,intinit_value){ unionsemunsem_union; sem_union.val=init_value; /*init_value為初始值*/ if(semctl(sem_id,0,SETVAL,sem_union)==-1) { perror("Initializesemaphore"); return-1; } return0;}67
4.4.2信號(hào)量編程信號(hào)量相關(guān)函數(shù)的封裝4.4信號(hào)量/*從系統(tǒng)中刪除信號(hào)量的函數(shù)*/intdel_sem(intsem_id){ unionsemunsem_union; if(semctl(sem_id,0,IPC_RMID,sem_union)==-1) { perror("Deletesemaphore"); return-1; }}68
4.4.2信號(hào)量編程信號(hào)量相關(guān)函數(shù)的封裝4.4信號(hào)量/*P操作函數(shù)*/intsem_p(intsem_id){ structsembufsem_b; sem_b.sem_num=0;/*單個(gè)信號(hào)量的編號(hào)應(yīng)該為0*/ sem_b.sem_op=-1;/*表示P操作*/ sem_b.sem_flg=SEM_UNDO; if(semop(sem_id,&sem_b,1)==-1) { perror("Poperation"); return-1; } return0;}69
4.4.2信號(hào)量編程信號(hào)量相關(guān)函數(shù)的封裝4.4信號(hào)量/*V操作函數(shù)*/intsem_v(intsem_id){ structsembufsem_b; sem_b.sem_num=0;/*單個(gè)信號(hào)量的編號(hào)應(yīng)該為0*/ sem_b.sem_op=1;/*表示V操作*/ sem_b.sem_flg=SEM_UNDO; if(semop(sem_id,&sem_b,1)==-1) { perror("Voperation"); return-1; } return0;}70
4.4.2信號(hào)量編程——示例4.4信號(hào)量71
共享內(nèi)存是一種最為高效的進(jìn)程間通信方式,進(jìn)程可以直接讀寫內(nèi)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年結(jié)構(gòu)化布線系統(tǒng)的檢測(cè)設(shè)備合作協(xié)議書
- 冀教版數(shù)學(xué)九年級(jí)下冊(cè)《30.3 由不共線三點(diǎn)的坐標(biāo)確定二次函數(shù)》聽評(píng)課記錄1
- 生產(chǎn)技術(shù)合同范本(2篇)
- 甘肅省就業(yè)協(xié)議書(2篇)
- 北師大版歷史七年級(jí)下冊(cè)第19課《明清經(jīng)濟(jì)繁盛與清前期盛世輝煌》聽課評(píng)課記錄
- 人教版數(shù)學(xué)八年級(jí)下冊(cè)聽評(píng)課記錄:第16章 二次根式的乘除法(二)
- 新北師大版小學(xué)數(shù)學(xué)一年級(jí)上冊(cè)《分類》聽評(píng)課記錄
- 中圖版歷史七年級(jí)下冊(cè)第14課《明朝的對(duì)外交往與抗倭斗爭(zhēng)》聽課評(píng)課記錄
- 蘇科版數(shù)學(xué)九年級(jí)上冊(cè)《切線》聽評(píng)課記錄
- 統(tǒng)編版初中語(yǔ)文九年級(jí)下冊(cè)第十六課《驅(qū)遣我們的想象》聽評(píng)課記錄
- 多學(xué)科視域中的歷史動(dòng)物研究綜述
- 知名企業(yè)建筑工程抹灰工程標(biāo)準(zhǔn)規(guī)范圖示手冊(cè)
- 重大事故隱患排查治理
- 2025保安部年度工作計(jì)劃
- 寵物貓護(hù)理教學(xué)
- 2024年江蘇經(jīng)貿(mào)職業(yè)技術(shù)學(xué)院?jiǎn)握新殬I(yè)適應(yīng)性測(cè)試題庫(kù)
- 圖書借閱登記表
- 中華人民共和國(guó)能源法
- 人居環(huán)境綜合治理項(xiàng)目項(xiàng)目背景及必要性分析
- 招標(biāo)采購(gòu)基礎(chǔ)知識(shí)培訓(xùn)
評(píng)論
0/150
提交評(píng)論