版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
12進(jìn)程間通信-PIPE
進(jìn)程間通信―FIFO
3信號(hào)中斷處理
進(jìn)程間通信——管道和信號(hào)進(jìn)程通信有如下一些目的:
A、數(shù)據(jù)傳輸:一個(gè)進(jìn)程需要將它的數(shù)據(jù)發(fā)送給另一個(gè)進(jìn)程,發(fā)送的數(shù)據(jù)量在一個(gè)字節(jié)到幾M字節(jié)之間;
B、共享數(shù)據(jù):多個(gè)進(jìn)程想要操作共享數(shù)據(jù),一個(gè)進(jìn)程對(duì)共享數(shù)據(jù)的修改,別的進(jìn)程應(yīng)該立刻看到;
C、通知事件:一個(gè)進(jìn)程需要向另一個(gè)或一組進(jìn)程發(fā)送消息,通知它(們)發(fā)生了某種事件(如進(jìn)程終止時(shí)要通知父進(jìn)程);
D、資源共享:多個(gè)進(jìn)程之間共享同樣的資源。為了做到這一點(diǎn),需要內(nèi)核提供鎖和同步機(jī)制;
E、進(jìn)程控制:有些進(jìn)程希望完全控制另一個(gè)進(jìn)程的執(zhí)行(如Debug進(jìn)程),此時(shí)控制進(jìn)程希望能夠攔截另一個(gè)進(jìn)程的所有陷入和異常,并能夠及時(shí)知道它的狀態(tài)改變。2023/2/12進(jìn)程間通信的方式linux下的進(jìn)程通信手段基本上是從Unix平臺(tái)上的進(jìn)程通信手段繼承而來(lái)的。而對(duì)Unix發(fā)展做出重大貢獻(xiàn)的兩大主力AT&T的貝爾實(shí)驗(yàn)室及BSD(加州大學(xué)伯克利分校的伯克利軟件發(fā)布中心)在進(jìn)程間通信方面的側(cè)重點(diǎn)有所不同。前者對(duì)Unix早期的進(jìn)程間通信手段進(jìn)行了系統(tǒng)的改進(jìn)和擴(kuò)充,形成了“systemVIPC”,通信進(jìn)程局限在單個(gè)計(jì)算機(jī)內(nèi);后者則跳過(guò)了該限制,形成了基于套接口(socket)的進(jìn)程間通信機(jī)制。Linux則把兩者繼承了下來(lái),其中,最初UnixIPC包括:管道、FIFO、信號(hào);SystemVIPC包括:SystemV消息隊(duì)列、SystemV信號(hào)量、SystemV共享內(nèi)存區(qū);PosixIPC包括:Posix消息隊(duì)列、Posix信號(hào)量、Posix共享內(nèi)存區(qū)。2023/2/13Linux進(jìn)程通信方式linux下進(jìn)程間通信的幾種主要手段簡(jiǎn)介:1、管道(Pipe)及有名管道(namedpipe):管道可用于具有親緣關(guān)系進(jìn)程間的通信,有名管道克服了管道沒(méi)有名字的限制,因此,除具有管道所具有的功能外,它還允許無(wú)親緣關(guān)系進(jìn)程間的通信;2、信號(hào)(Signal):信號(hào)是比較復(fù)雜的通信方式,用于通知接受進(jìn)程有某種事件發(fā)生,除了用于進(jìn)程間通信外,進(jìn)程還可以發(fā)送信號(hào)給進(jìn)程本身;linux除了支持Unix早期信號(hào)語(yǔ)義函數(shù)signal外,還支持語(yǔ)義符合Posix.1標(biāo)準(zhǔn)的信號(hào)函數(shù)sigaction。2023/2/14Linux進(jìn)程通信方式3、報(bào)文(Message)隊(duì)列(消息隊(duì)列):消息隊(duì)列是消息的鏈接表。有足夠權(quán)限的進(jìn)程可以向隊(duì)列中添加消息,被賦予讀權(quán)限的進(jìn)程則可以讀走隊(duì)列中的消息。消息隊(duì)列克服了信號(hào)承載信息量少,管道只能承載無(wú)格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)。4、共享內(nèi)存:使得多個(gè)進(jìn)程可以訪問(wèn)同一塊內(nèi)存空間,是最快的可用IPC形式。是針對(duì)其他通信機(jī)制運(yùn)行效率較低而設(shè)計(jì)的。往往與其它通信機(jī)制,如信號(hào)量結(jié)合使用,來(lái)達(dá)到進(jìn)程間的同步及互斥。5、信號(hào)量(semaphore):主要作為進(jìn)程間以及同一進(jìn)程不同線程之間的同步手段。2023/2/15管道管道的實(shí)質(zhì)是一個(gè)內(nèi)核緩沖區(qū),進(jìn)程以先進(jìn)先出的方式從緩沖區(qū)中存取數(shù)據(jù):管道一端的進(jìn)程順序地將數(shù)據(jù)寫(xiě)入緩沖區(qū),另一端的進(jìn)程則順序地讀出數(shù)據(jù)。該緩沖區(qū)可以看作是一個(gè)循環(huán)隊(duì)列,讀和寫(xiě)的位置都是自動(dòng)增加的,不能隨意改變,一個(gè)數(shù)據(jù)只能被讀一次,讀出以后在緩沖區(qū)中就不復(fù)存在了。當(dāng)緩沖區(qū)讀空或?qū)憹M時(shí),有一定的規(guī)則控制相應(yīng)的讀進(jìn)程或?qū)戇M(jìn)程是否進(jìn)入等待隊(duì)列;當(dāng)空的緩沖區(qū)有新數(shù)據(jù)寫(xiě)入或滿的緩沖區(qū)有數(shù)據(jù)讀出時(shí),就喚醒等待隊(duì)列中的進(jìn)程繼續(xù)讀寫(xiě)。2023/2/16管道管道實(shí)際上以類(lèi)似文件的方式與進(jìn)程交互,但它并不與磁盤(pán)打交道,所以效率要比文件操作高很多。它有兩個(gè)局限性:(1)支持半雙工;(2)只有具有親緣關(guān)系的進(jìn)程之間才能使用這種無(wú)名管道;使用管道的注意事項(xiàng):1.當(dāng)讀一個(gè)寫(xiě)端已經(jīng)關(guān)閉的管道時(shí),在所有數(shù)據(jù)被讀取之后,read函數(shù)返回值為0,以指示到了文件結(jié)束處;2.如果寫(xiě)一個(gè)讀端關(guān)閉的管道,則產(chǎn)生SIGPIPE信號(hào)。如果忽略該信號(hào)或者捕捉該信號(hào)并處理程序返回,則write返回-1,errno設(shè)置為EPIPE2023/2/17管道示例例如$ls|more功能是將ls命令的輸出作為more命令的輸入,并顯示more的最終輸出。這里ls與more要由兩個(gè)進(jìn)程來(lái)完成。這兩個(gè)進(jìn)程的通信就通過(guò)父進(jìn)程shell創(chuàng)建管道。ls向管道輸入數(shù)據(jù),more從管道讀出數(shù)據(jù)。2023/2/18stdinstdinstdoutstdoutstderrstderrlsmore管道連接管道用于不同進(jìn)程間通信。通常先創(chuàng)建一個(gè)管道,再通過(guò)fork函數(shù)創(chuàng)建一個(gè)子進(jìn)程,該子進(jìn)程會(huì)繼承父進(jìn)程所創(chuàng)建的管道。創(chuàng)建無(wú)名管道externintpipe(int__pipedes[2])此函數(shù)的參數(shù)是一個(gè)整型數(shù)組。如果執(zhí)行成功,pipe將存儲(chǔ)兩個(gè)整形文件描述符于__pipedes數(shù)組中,它們分別指向管道的兩端。如果系統(tǒng)調(diào)用失敗,將返回-1。2023/2/110注意:fd[0]用于讀取管道,fd[1]用于寫(xiě)入管道。圖1linux中管道與文件描述符的關(guān)系#include<unistd.h>#include<errno.h>#include<stdio.h>#include<stdlib.h>intmain(){ intpipe_fd[2]; if(pipe(pipe_fd)<0){ printf("pipecreateerror\n"); return-1; } else printf("pipecreatesuccess\n"); close(pipe_fd[0]); close(pipe_fd[1]);}管道讀寫(xiě)管道主要用于不同進(jìn)程間通信。實(shí)際上,通常先創(chuàng)建一個(gè)管道,再通過(guò)fork函數(shù)創(chuàng)建一個(gè)子進(jìn)程。圖2父子進(jìn)程管道的文件描述符對(duì)應(yīng)關(guān)系子進(jìn)程寫(xiě)入和父進(jìn)程讀的命名管道:圖
關(guān)閉父進(jìn)程fd[1]和子進(jìn)程fd[0]例:父子進(jìn)程通過(guò)無(wú)名管道通信#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/wait.h>#include<unistd.h>#include<string.h>main(){ pid_tresult; intr_num; intpipe_fd[2]; charbuf_r[100],buf_w[100];
memset(buf_r,0,sizeof(buf_r));2023/2/115例:父子進(jìn)程通過(guò)無(wú)名管道通信 if(pipe(pipe_fd)<0) { perror("pipe"); exit(EXIT_FAILURE); } result=fork(); if(result<0) { perror("fork"); exit(EXIT_FAILURE); } elseif(result==0) { close(pipe_fd[1]); if((r_num=read(pipe_fd[0],buf_r,100))>0) printf("childprocesshasread%dcharactersfromthepipe,thestringis:%s\n",r_num,buf_r); close(pipe_fd[0]); exit(0); }2023/2/116例:父子進(jìn)程通過(guò)無(wú)名管道通信 else { close(pipe_fd[0]); printf("pleaseinputthestring:"); scanf("%s",buf_w); if(write(pipe_fd[1],buf_w,strlen(buf_w))!=-1) printf("parentprocesshaswritten:%stothepipe!\n",buf_w); close(pipe_fd[1]); waitpid(result,NULL,0); exit(0); }}2023/2/117dup()externintdup(int__fd)dup()會(huì)復(fù)制一份原來(lái)已經(jīng)打開(kāi)的文件描述符,新的描述符指向系統(tǒng)文件表中下一個(gè)可用的最小非負(fù)文件描述符,它與原來(lái)的文件描述符共享同一個(gè)文件指針,并擁有相同的文件權(quán)限及模式。當(dāng)調(diào)用dup()時(shí),總返回下一個(gè)最小的可用文件描述符。例如:下面語(yǔ)句即可以將輸出重定向到管道:intf_des[2];pipe(f_des);close(fileno(stdout));dup(f_des[1])此后,所有寫(xiě)向標(biāo)準(zhǔn)輸出的數(shù)據(jù)都將寫(xiě)入到管道中。因此,要復(fù)制標(biāo)準(zhǔn)輸出輸入設(shè)備,應(yīng)先關(guān)閉這一設(shè)備,然后再?gòu)?fù)制。2023/2/118復(fù)制文件描述符2023/2/119dup2()externintdup2(int__fd,int__fd2)dup2()有兩個(gè)參數(shù),fd和fd2,fd2是小于文件描述符的最大允許值的非負(fù)整數(shù)。如果fd2是一個(gè)已打開(kāi)的文件描述符,則首先關(guān)閉該文件,然后再?gòu)?fù)制。2023/2/120綜合應(yīng)用舉例#include<errno.h>#include<sys/wait.h>#include<stdio.h>#include<stdlib.h>#include<unistd.h>#defineDEF_PAGER"/bin/more“#defineMAXLINE10main(intargc,char*argv[]){ intn; intfd[2]; pid_tpid; char*pager,*argv0; charline[MAXLINE]; FILE*fp;2023/2/121綜合應(yīng)用舉例 if(argc!=2) { printf("errorusage!\n"); exit(EXIT_FAILURE); } if((fp=fopen(argv[1],"r"))==NULL) { perror("open"); exit(EXIT_FAILURE); } if(pipe(fd)<0) { perror("pipe"); exit(EXIT_FAILURE); } if((pid=fork())<0) { perror("fork"); exit(EXIT_FAILURE); }
2023/2/122綜合應(yīng)用舉例 if(pid>0) { close(fd[0]); while(fgets(line,MAXLINE,fp)!=NULL) { n=strlen(line); if(write(fd[1],line,n)!=n) { perror("write"); exit(EXIT_FAILURE); }} close(fd[1]); if(waitpid(pid,NULL,0)<0) { perror("wait"); exit(EXIT_FAILURE); } exit(0); }
2023/2/123綜合應(yīng)用舉例 else { close(fd[1]); if(fd[0]!=STDIN_FILENO) { if(dup2(fd[0],STDIN_FILENO)!=STDIN_FILENO) { perror("dup"); exit(EXIT_FAILURE); } close(fd[0]); } if((pager=getenv("PAGER"))==NULL) pager=DEF_PAGER; if((argv0=strrchr(pager,'/'))!=NULL) argv0++; else argv0=pager; if(execl(pager,argv0,(char*)0)<0) { perror("exec"); exit(EXIT_FAILURE); } exit(0); }}2023/2/124流重定向externFILE*popen(__constchar*__command,__constchar*__modes);popen函數(shù)創(chuàng)建一個(gè)子進(jìn)程,并在子進(jìn)程中執(zhí)行第一個(gè)參數(shù)程序,同時(shí)返回一個(gè)文件指針,即第一個(gè)參數(shù)*__command指向要執(zhí)行的命令的指針。第二個(gè)參數(shù)表示I/O模式的類(lèi)型。如果此命令的輸出將作為其他命令的輸入,即輸出重定向,則需要設(shè)置其第二個(gè)參數(shù)為“r”權(quán)限;如果此命令的輸入數(shù)據(jù)要從其他命令的輸出數(shù)據(jù),即輸入重定向,則需要設(shè)置其第二個(gè)參數(shù)為“w”權(quán)限;在使用完重定向后,需要使用pclose()關(guān)閉相應(yīng)的流對(duì)象,該函數(shù)聲明如下:externintpclose(FILE*__stream);2023/2/125例:流重定向的應(yīng)用#include<errno.h>//#include<sys/wait.h>#include<stdio.h>#include<stdlib.h>#include<unistd.h>#definePAGER"${PAGER:-more}“#defineMAXLINE10main(intargc,char*argv[]){ charline[MAXLINE]; FILE*fpin,*fpout; if(argc!=2) { printf("errorusage!\n"); exit(EXIT_FAILURE); }2023/2/126例:流重定向的應(yīng)用 if((fpin=fopen(argv[1],"r"))==NULL) { perror("open"); exit(EXIT_FAILURE); } if((fpout=popen(PAGER,"w"))==NULL) { perror("popen"); exit(EXIT_FAILURE); } while(fgets(line,MAXLINE,fpin)!=NULL) { if(fputs(line,fpout)==EOF) { perror("fputs"); exit(EXIT_FAILURE); } } if(pclose(fpout)==-1) { perror("pclose"); exit(EXIT_FAILURE); } exit(0);}2023/2/127注意事項(xiàng):1.如果所有指向管道寫(xiě)端的文件描述符都關(guān)閉了,而仍然有進(jìn)程從管道的讀端讀數(shù)據(jù),那么管道中剩余的數(shù)據(jù)都被讀取后,再次read會(huì)返回0,就像讀到文件末尾一樣。2.如果有指向管道寫(xiě)端的文件描述符沒(méi)有關(guān)閉,而持有管道寫(xiě)端的進(jìn)程也沒(méi)有向管道中寫(xiě)數(shù)據(jù),這時(shí)有進(jìn)程從管道讀端讀數(shù)據(jù),那么管道中剩余的數(shù)據(jù)都被讀取后,再次read會(huì)阻塞,直到管道中有數(shù)據(jù)可讀了才讀取數(shù)據(jù)并返回。3.如果所有指向管道讀端的文件描述符都關(guān)閉了,這時(shí)有進(jìn)程向管道的寫(xiě)端write,那么該進(jìn)程會(huì)收到信號(hào)SIGPIPE,通常會(huì)導(dǎo)致進(jìn)程異常終止。2023/2/128注意事項(xiàng):4.如果有指向管道讀端的文件描述符沒(méi)有關(guān)閉,而持有管道讀端的進(jìn)程也沒(méi)有從管道中讀數(shù)據(jù),這時(shí)有進(jìn)程向管道寫(xiě)端寫(xiě)數(shù)據(jù),那么在管道被寫(xiě)滿時(shí)再次write會(huì)阻塞,直到管道中有空位置了才寫(xiě)入數(shù)據(jù)并返回。5.兩個(gè)進(jìn)程通過(guò)一個(gè)管道只能實(shí)現(xiàn)單向通信,如果有時(shí)候也需要子進(jìn)程寫(xiě)父進(jìn)程讀,就必須另開(kāi)一個(gè)管道。2023/2/129進(jìn)程間通信-管道和信號(hào)12進(jìn)程間通信-PIPE
進(jìn)程間通信―FIFO
3信號(hào)中斷處理
FIFOFIFO就是命名管道,或有名管道。它同樣是基于VFS,對(duì)應(yīng)的文件類(lèi)型就是FIFO文件,可以通過(guò)mknod命令在磁盤(pán)上創(chuàng)建一個(gè)FIFO文件。當(dāng)進(jìn)程想通過(guò)該FIFO來(lái)通信時(shí)就可以標(biāo)準(zhǔn)的APIopen(close、read、write、unlink等)打開(kāi)該文件,然后開(kāi)始讀寫(xiě)操作。對(duì)于FIFO的讀寫(xiě)實(shí)現(xiàn),它與pipe是相同的。區(qū)別在于,F(xiàn)IFO有open這一操作,而pipe是在調(diào)用pipe這個(gè)系統(tǒng)調(diào)用時(shí)直接創(chuàng)建了一對(duì)文件描述符用于通信。并且,F(xiàn)IFO的open操作還有些細(xì)致的地方要考慮,例如如果寫(xiě)者先打開(kāi),尚無(wú)讀者,那么肯定是不能通信了,所以就需要先去睡眠等待讀者打開(kāi)該FIFO,反之對(duì)讀者亦然。2023/2/131用途FIFO由shell命令使用以便將數(shù)據(jù)從一條管道線傳送到另一條,為此無(wú)需創(chuàng)建中間臨時(shí)文件。FIFO用于客戶進(jìn)程-服務(wù)器進(jìn)程應(yīng)用程序中,以在客戶進(jìn)程和服務(wù)器進(jìn)程之間傳遞數(shù)據(jù)。2023/2/132創(chuàng)建FIFO/CreateanewFIFOnamedPATH,withpermissionbitsMODE.*/externintmkfifo(__comstchar*__path,__mode_t__mode)mkfifo()會(huì)根據(jù)參數(shù)建立特殊的有名管道文件,該文件必須不存在,而參數(shù)mode為該文件的授權(quán),mkfifo()建立的FIFO文件其他進(jìn)程都可以用讀寫(xiě)一般文件的方式存取。當(dāng)使用open()函數(shù)打開(kāi)FIFO文件時(shí),O_NONBLOCK會(huì)有影響。如果執(zhí)行成功將返回0,否則返回-1,失敗原因存儲(chǔ)于errno中。2023/2/133例:命名管道的使用#include<sys/types.h>#include<sys/fcntl.h>#include<fcntl.h>#include<stdlib.h>#include<stdio.h>#defineFIFO"/tmp/fifo“main(){ pid_tpid; charbuffer[80]; intfd; unlink(FIFO); mkfifo(FIFO,0744);2023/2/134例:命名管道的使用 if((pid=fork())>0) { chars[]="Hello!"; fd=open(FIFO,O_WRONLY); printf("thisisfatherwritedatais%s\n",s); printf("father'spidis%d\n",getpid()); write(fd,s,sizeof(s)); close(fd); exit(0); }
2023/2/135例:命名管道的使用 elseif(pid==0) { sleep(2); fd=open(FIFO,O_RDONLY); read(fd,buffer,80); printf("thisischildreaddatais:%s\n",buffer); close(fd); printf("child'spidis%d\n",getpid()); exit(0); }}2023/2/136管道基本特點(diǎn)總結(jié)兩類(lèi)型管道具有以下特點(diǎn):(1)管道是特殊類(lèi)型的文件,在滿足先入先出的原則條件下可能進(jìn)行讀寫(xiě),但不能定位讀寫(xiě)位置。(2)管道是單向的,要實(shí)現(xiàn)雙向,需要兩個(gè)管道。無(wú)名管道只能實(shí)現(xiàn)親緣關(guān)系進(jìn)程間通信(即無(wú)名管道的兩個(gè)文件描述符可以被兩者都訪問(wèn)到),而有名管道以磁盤(pán)文件的方式存在,可以實(shí)現(xiàn)本機(jī)任意兩進(jìn)程間通信。2023/2/137管道基本特點(diǎn)總結(jié)(續(xù))(3)無(wú)名管道阻塞問(wèn)題。無(wú)名管道無(wú)須顯式打開(kāi),創(chuàng)建時(shí)直接返回文件描述符,而在讀寫(xiě)時(shí)需要確實(shí)對(duì)方的存在,否則將退出。即如果當(dāng)前進(jìn)程向無(wú)名管道的一端寫(xiě)數(shù)據(jù)時(shí),必須確定其另一端為某個(gè)進(jìn)程(這個(gè)進(jìn)程可以是當(dāng)前進(jìn)程)擁有。如果寫(xiě)入無(wú)名管道的數(shù)據(jù)超過(guò)其最大值,寫(xiě)操作將阻塞,如果管道中沒(méi)有數(shù)據(jù),讀操作將阻塞,如果管道發(fā)現(xiàn)另一端斷開(kāi)(另一端文件描述符關(guān)閉),將自動(dòng)退出。2023/2/138管道基本特點(diǎn)總結(jié)(續(xù))(4)有名管道阻塞問(wèn)題。有名管道在打開(kāi)時(shí)需要確實(shí)對(duì)方的存在,否則將阻塞。即以讀方式打開(kāi)某管道,該操作得以繼續(xù)執(zhí)行的條件是:在此之前,已經(jīng)有一個(gè)進(jìn)程以寫(xiě)的方式打開(kāi)此管道,否則阻塞,直到條件滿足,因此有名管道將阻塞在打開(kāi)位置。也可以以讀寫(xiě)(O_RDWR)方式打開(kāi)有名管道,進(jìn)程能夠繼續(xù)執(zhí)行(不阻塞),即當(dāng)前進(jìn)程讀,當(dāng)前進(jìn)程寫(xiě)。2023/2/139進(jìn)程間通信-管道和信號(hào)12進(jìn)程間通信-PIPE
進(jìn)程間通信―FIFO
3信號(hào)中斷處理
信號(hào)概述信號(hào)是Linux系統(tǒng)中用于進(jìn)程之間相互通信或操作的一種機(jī)制。信號(hào)可以在任何時(shí)候發(fā)給某一進(jìn)程,而無(wú)需知道該進(jìn)程的狀態(tài)。如果該進(jìn)程當(dāng)前并未處于執(zhí)行狀態(tài),則該信號(hào)就由內(nèi)核保存起來(lái),直到該進(jìn)程恢復(fù)執(zhí)行并傳遞給它為止;如果一個(gè)信號(hào)被進(jìn)程設(shè)置為阻塞,則該信號(hào)的傳遞被延遲,直到其阻塞被取消時(shí)才被傳遞給進(jìn)程。進(jìn)程之間可以互相通過(guò)系統(tǒng)調(diào)用kill發(fā)送軟中斷信號(hào)。內(nèi)核也可以因?yàn)閮?nèi)部事件而給進(jìn)程發(fā)送信號(hào),通知進(jìn)程發(fā)生了某個(gè)事件。信號(hào)機(jī)制除了基本通知功能外,還可以傳遞附加信息。2023/2/141Linux信號(hào)2023/2/142//comefromasm/signal.h常見(jiàn)的信號(hào)Linux系統(tǒng)中常見(jiàn)的信號(hào)說(shuō)明如下:1)SIGHUP:用戶從終端注銷(xiāo)時(shí),所有已啟動(dòng)的進(jìn)程都將收到SIGHUP信號(hào)。系統(tǒng)缺省狀態(tài)下對(duì)該信號(hào)的處理就是中止進(jìn)程。2)SIGINT:程序終止信號(hào)。在程序運(yùn)行過(guò)程中,用戶通過(guò)鍵盤(pán)按下【Ctrl】+【C】鍵將產(chǎn)生該信號(hào)。3)SIGQUIT:程序退出信號(hào)。在程序運(yùn)行過(guò)程中,用戶通過(guò)按下【Ctrl】+【\】鍵將產(chǎn)生該信號(hào)。4)SIGBUS和SIGSEGV:進(jìn)程訪問(wèn)非法地址時(shí),引發(fā)該信號(hào)。5)SIGFPE:進(jìn)行算術(shù)運(yùn)算中出現(xiàn)致命錯(cuò)誤,如除零操作、數(shù)據(jù)溢出等。2023/2/143常見(jiàn)的信號(hào)(續(xù))6)SIGKILL:終止用戶進(jìn)程執(zhí)行的信號(hào)。在shell下通過(guò)執(zhí)行“kill-9”命令發(fā)送的就是該信號(hào)。7)SIGTERM:進(jìn)程結(jié)束信號(hào)。在shell下執(zhí)行“kill進(jìn)程pid”命令發(fā)送的就是該信號(hào)。8)SIGALRM:定時(shí)器信號(hào)。9)SIGCLD:子進(jìn)程退出信號(hào)。如果父進(jìn)程沒(méi)有忽略該信號(hào),也沒(méi)有處理該信號(hào),則子進(jìn)程退出后將形成僵尸進(jìn)程。2023/2/144信號(hào)的分類(lèi)可靠信號(hào):也稱為實(shí)時(shí)信號(hào),支持排隊(duì)。不可靠信號(hào):非實(shí)時(shí)信號(hào),不支持排隊(duì)。發(fā)送用戶進(jìn)程判斷后注冊(cè),發(fā)現(xiàn)相同信號(hào)已經(jīng)在進(jìn)程中注冊(cè),就不再注冊(cè),忽略該信號(hào)。2023/2/145可能的信號(hào)來(lái)源信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,是一種異步通信方式。信號(hào)可以在用戶空間進(jìn)程和內(nèi)核之間直接交互,內(nèi)核也可以利用信號(hào)來(lái)通知用戶空間的進(jìn)程發(fā)生了哪些系統(tǒng)事件。信號(hào)事件的發(fā)生有兩個(gè)來(lái)源:1.硬件來(lái)源:用戶按某些終端鍵時(shí)將產(chǎn)生信號(hào),如CTRL+C將產(chǎn)生SIGINT(中止信號(hào));硬件異常產(chǎn)生信號(hào),如除數(shù)為0或無(wú)效的存儲(chǔ)訪問(wèn)等。2.軟件來(lái)源:終止進(jìn)程信號(hào),其他進(jìn)程調(diào)用kill函數(shù),將信號(hào)發(fā)送個(gè)另一個(gè)進(jìn)程或進(jìn)程組;軟件異常產(chǎn)生信號(hào)。2023/2/146信號(hào)的處理流程(1)信號(hào)被某個(gè)進(jìn)程產(chǎn)生,并設(shè)置此信號(hào)傳遞的對(duì)象(一般為對(duì)應(yīng)進(jìn)程的pid),然后傳遞給操作系統(tǒng);(2)操作系統(tǒng)根據(jù)接收進(jìn)程的設(shè)置(是否阻塞)而選擇性的發(fā)送給接收者,如果接收者阻塞該信號(hào)(且該信號(hào)是可以阻塞的),操作系統(tǒng)將暫時(shí)保留該信號(hào),而不傳遞,直到該進(jìn)程解除對(duì)此信號(hào)的阻塞(如果對(duì)應(yīng)進(jìn)程已經(jīng)退出,則丟棄此信號(hào));如果對(duì)應(yīng)進(jìn)程沒(méi)有阻塞,操作系統(tǒng)將傳遞此信號(hào);(3)目的進(jìn)程接收到此信號(hào)后,將根據(jù)當(dāng)前進(jìn)程對(duì)此信號(hào)設(shè)置的預(yù)處理方式,暫時(shí)終止當(dāng)前代碼的執(zhí)行,保護(hù)上下文(主要包括臨時(shí)寄存器數(shù)據(jù)、當(dāng)前程序位置以及當(dāng)前CPU的狀態(tài))、轉(zhuǎn)而執(zhí)行中斷服務(wù)程序,執(zhí)行完成后再恢復(fù)到被中斷的位置。當(dāng)然,對(duì)于可搶占式內(nèi)核,在中斷返回時(shí)還將引發(fā)新的調(diào)度。2023/2/147信號(hào)的生命周期信號(hào)處理信號(hào)產(chǎn)生信號(hào)注冊(cè)信號(hào)注銷(xiāo)內(nèi)核進(jìn)程用戶進(jìn)程2023/2/148kill產(chǎn)生一個(gè)信號(hào)kill()函數(shù)用來(lái)向指定進(jìn)程發(fā)送一個(gè)信號(hào)。此函數(shù)聲明如下://comefrom/usr/include/signal.hexternintkill(__pid_t__pid,int__sig)此函數(shù)的第一個(gè)參數(shù)為要傳遞信號(hào)的進(jìn)程號(hào)(PID),第二個(gè)參數(shù)即發(fā)送的信號(hào)值。pid可以取以下幾種值:pid>o:將信號(hào)發(fā)送給進(jìn)程的PID值為pid的進(jìn)程。pid=0:將信號(hào)發(fā)送給和當(dāng)前進(jìn)程在同一進(jìn)程組的所有進(jìn)程。pid=-1:將信號(hào)發(fā)送給系統(tǒng)內(nèi)的所有進(jìn)程。pid<0:將信號(hào)發(fā)送給進(jìn)程組號(hào)PGID為pid絕對(duì)值的所有進(jìn)程。如果成功完成返回值0,否則返回-1,并設(shè)置errno以指示錯(cuò)誤。2023/2/149#include<stdio.h>#include<signal.h>voidmain(intargc,char*argv[]) { intpid,signo; if(argc!=3) { printf("usage:killsenderpidsigno\n"); return; } sscanf(argv[1],"%d",&pid);//獲取參數(shù)pid
sscanf(argv[2],"%d",&signo);//獲取參數(shù)signo
if(kill(pid,signo)<0) {//發(fā)送信號(hào) perror("kill"); return; } printf("ok:sendoutsignalviakillsystemcall!\n");}2023/2/150例:編寫(xiě)程序killsender。通過(guò)kill系統(tǒng)調(diào)用向指定進(jìn)程(pid)發(fā)送信號(hào)。raise自舉一個(gè)信號(hào)raise()函數(shù)用來(lái)給當(dāng)前進(jìn)程發(fā)送一個(gè)信號(hào),即喚醒一個(gè)進(jìn)程。此函數(shù)聲明如下://comefrom/usr/include/signal.h/*RaisesignalSIG,i.e.,sendSIGtoyourself.*/externintraise(int__sig)此函數(shù)相當(dāng)于采用以下方式執(zhí)行kill()函數(shù):if(kill(getpid(),int__sig)==-1)
perror(“raise”);2023/2/151例:設(shè)計(jì)一個(gè)程序,創(chuàng)建一個(gè)子進(jìn)程,父進(jìn)程向子進(jìn)程發(fā)出信號(hào),子進(jìn)程收到此信號(hào),結(jié)束子進(jìn)程的運(yùn)行。#include<stdio.h>#include<signal.h>#include<sys/wait.h>#include<unistd.h>#include<stdlib.h>intmain(){ pid_tresult; intret; result=fork(); intnewret;
2023/2/152 if(result<0) { perror("fork"); exit(EXIT_FAILURE); } elseif(result==0) { raise(SIGSTOP); exit(0); } else { printf("child'spid=%d\n",result); if((waitpid(result,NULL,WNOHANG))==0) { if(ret=kill(result,SIGKILL)==0) printf("killfunctionfinished%dprocesswithreturnvalue=%d\n",result,ret); else { perror("kill"); } } }}2023/2/153alarm()定時(shí)alarm()函數(shù)用來(lái)傳遞定時(shí)信號(hào),即在多少時(shí)間內(nèi)產(chǎn)生SIGALRM信號(hào),此函數(shù)每調(diào)用一次,產(chǎn)生一個(gè)信號(hào),并不是循環(huán)產(chǎn)生SIGALRM信號(hào)。//comefrom/usr/include/unistd.hexternunsignedintalarm(unsignedint__seconds)此函數(shù)只有一個(gè)參數(shù),即在多少時(shí)間(秒)內(nèi)發(fā)送SIGALRM信號(hào)給當(dāng)前進(jìn)程,默認(rèn)情況下,當(dāng)進(jìn)程接受到alarm信號(hào)后將終止執(zhí)行;如果sec為0,則取消所有先前發(fā)出的報(bào)警請(qǐng)求。如果在調(diào)用alarm()函數(shù)前沒(méi)有調(diào)用過(guò)alarm()函數(shù),如果執(zhí)行成功,將返回0,否則返回-1,并置errno標(biāo)致錯(cuò)誤。2023/2/154例:alarm的使用#include<stdio.h>#include<signal.h>intmain(){ printf("firsttimereturn:%d\n",alarm(4)); sleep(1); printf("aftersleep(1),remain:%d\n",alarm(2)); printf("renewalarm,remain:%d\n",alarm(1));}2023/2/155ualarm定時(shí)ualarm將使當(dāng)前進(jìn)程在指定時(shí)間(第一個(gè)參數(shù),以u(píng)s為單位)內(nèi)產(chǎn)生SIGALRM信號(hào),然后每隔指定時(shí)間(第二個(gè)參數(shù),以u(píng)s為單位)重復(fù)產(chǎn)生SIGALRM信號(hào)。如果執(zhí)行成功將返回0,該函數(shù)聲明如下:extern__useconds_tualarm(__useconds_t__value,__useconds_t__interval)2023/2/156信號(hào)處理與signal安裝信號(hào)信號(hào)處理辦法:(1)忽略此信號(hào)。大多數(shù)信號(hào)都可使用這種方式進(jìn)行處理,但有兩種信號(hào)不能被忽略,SIGKILL和SIGSTOP。這兩種信號(hào)不能被忽略的原因是:它們向超級(jí)用戶提供一種使進(jìn)程終止或停止的可靠方法。(2)捕捉信號(hào)。通知內(nèi)核在某種信號(hào)發(fā)生時(shí)調(diào)用一個(gè)用戶函數(shù)。在用戶函數(shù)中,可執(zhí)行用戶希望對(duì)這種事件進(jìn)行的處理,這需要安裝此信號(hào)。例如捕捉到SIGCHLD信號(hào),則表示子進(jìn)程已經(jīng)終止,所以此信號(hào)的捕捉函數(shù)可以調(diào)用waitpid()以取得該子進(jìn)程的進(jìn)程PID以及它的終止?fàn)顟B(tài)和資源。(3)執(zhí)行系統(tǒng)默認(rèn)操作。Linux系統(tǒng)對(duì)任何一個(gè)信號(hào)都規(guī)定了一個(gè)默認(rèn)的操作。2023/2/157signal安裝信號(hào)typedefvoid(*__sighandler_t)(int);extern__sighander_tsignal(int__sig,sighandler_t__handler)此函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)sig為接收到的信號(hào),第二個(gè)參數(shù)為接收到此信號(hào)后的處理代碼入口或下面幾個(gè)宏:/*Fakesignalfunctions.*/#defineSIG_ERR((__sighandler_t)-1)/*Errorreturn.*/#defineSIG_DFL((__sighandler_t)0)/*Defaultaction.*/#defineSIG_IGN((__sighandler_t)1)/*Ignoresignal.*/2023/2/158例:編寫(xiě)程序:killrecerver和killsender。其中killrecerver用于接收SIGUSR1(值為10)信號(hào),而killsender通過(guò)kill系統(tǒng)調(diào)用向指定進(jìn)程(pid)發(fā)送信號(hào)。#include<stdio.h>#include<unistd.h>#include<sys/types.h>#include<signal.h>//SIGUSR1信號(hào)處理函數(shù)voidCbSigUsr1(intsigno){//輸出接收到的信號(hào)信息 printf("\nreceivesignal=%d.\n",signo);}2023/2/159voidmain() {//安裝SIGUSR1信號(hào) if(signal(SIGUSR1,CbSigUsr1)==SIG_ERR){ perror("signal"); return;} printf("mypidis%d\n",getpid()); printf("waitingforSIGUSR1...\n");//暫停,等待信號(hào) pause();}
2023/2/160例:signal的應(yīng)用#include<stdio.h>#include<signal.h>#include<unistd.h>#include<stdlib.h>voidfun_ctrl_c();intmain(){ (void)signal(SIGINT,fun_ctrl_c); printf("NowI'mstarting\n"); while(1) { printf("thisisanendlessloopunlessCtrl+carepressd!\n"); sleep(2); } exit(0);}2023/2/161例:signal的應(yīng)用voidfun_ctrl_c(){ printf("\tCtrl+cwerepressed!\n"); printf("\tThisisjustanexampleforsignalfunction!\n"); printf("\tresetsignalSIGINT\n"); (void)signal(SIGINT,SIG_DFL);}2023/2/162sigaction安裝信號(hào)externintsigaction(int__sig,structsigaction*__act,structsigaction*__oact)此函數(shù)的第一個(gè)參數(shù)為接收到的信號(hào),第二、三個(gè)參數(shù)均為信號(hào)結(jié)構(gòu)sigaction(用于描述要采取的操作及相關(guān)信息,見(jiàn)后續(xù)說(shuō)明)變量。第二個(gè)參數(shù)用來(lái)指定欲設(shè)置的信號(hào)處理信息,第三個(gè)參數(shù)將返回執(zhí)行此程序前信號(hào)處理信息。如果第二個(gè)參數(shù)act不為空指針,則指定信號(hào)關(guān)聯(lián)的操作為此參數(shù)指向的結(jié)構(gòu)。如果參數(shù)oact不為空指針,則用來(lái)存儲(chǔ)以前設(shè)置的與此信號(hào)關(guān)聯(lián)的操作。如果參數(shù)act為空指針,則信號(hào)處理保持不變;因此,該調(diào)用可用于詢問(wèn)對(duì)指定信號(hào)的當(dāng)前處理。2023/2/163structsigactionStructsigaction{ union{ __sighandler_t_sa_handler; void(*_sa_sigaction)(int,structsiginfo*,void*); }__u; sigset_tsa_mask; unsignedlongsa_flags; void(*sa_restorer)(void);};#definesa_handler_u.sa_handler#definesa_sigaction_u._sa_sigaction2023/2/164例:sigaction的應(yīng)用#include<stdio.h>#include<stdlib.h>#include<signal.h>voidmyhandler(intsig);intmain(){ structsigactionact,oact; act.sa_handler=myhandler; sigemptyset(&act.sa_mask); act.sa_flags=0; sigaction(SIGUSR1,&act,&oact); while(1) { printf("helloworld!\n"); pause(); }}2023/2/165voidmyhandler(intsig){ printf("thesignal%dwascaught.\n",sig);}信號(hào)集與屏蔽信號(hào)中斷是可以被屏蔽(阻塞)的(部分硬件中斷是必須立即處理的,例如復(fù)位中斷),因此,Linux的信號(hào)是可以屏蔽,即阻塞信號(hào)。但這與前面提到的忽略是有區(qū)別的。信號(hào)忽略:系統(tǒng)仍然傳遞該信號(hào),只是相應(yīng)進(jìn)程對(duì)該信號(hào)不作任何處理而已。信號(hào)阻塞:系統(tǒng)不傳遞該信號(hào),顯示該進(jìn)程無(wú)法接收到該信號(hào)直到進(jìn)程的信號(hào)集發(fā)生改變。2023/2/166sigprocmask設(shè)置進(jìn)程阻塞的信號(hào)集externintsigprocmask(int__how,__constsigset_t*__restrict__set,sigset_t*__restrict__oset)此函數(shù)第一個(gè)參數(shù)為更改該集合的方式,如下所示://comefrom/usr/include/asm/signal.h#defineSIG_BLOCK0/*forblockingsignals*/#defineSIG_UNBLOCK1
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年跨區(qū)域旅游聯(lián)盟運(yùn)營(yíng)合作協(xié)議
- 2024年裝修協(xié)議額外條款明細(xì)一
- 二零二五年人工智能教育合作協(xié)議3篇
- 2024年貨物供應(yīng)合同
- 2024年第三方物流運(yùn)輸服務(wù)合同模板
- 《結(jié)構(gòu)設(shè)計(jì)問(wèn)題解析》課件
- 幼兒園工作總結(jié)用心呵護(hù)每個(gè)小天使
- 餐飲行業(yè)保安工作計(jì)劃
- 汽車(chē)行業(yè)顧問(wèn)工作概述
- 手工藝品店前臺(tái)工作總結(jié)
- 2024養(yǎng)老院消防設(shè)備升級(jí)與消防系統(tǒng)維護(hù)服務(wù)合同3篇
- 單位內(nèi)部治安保衛(wèi)制度
- 人才引進(jìn)政策購(gòu)房合同模板
- 學(xué)生宿舍消防安全制度模版(3篇)
- 四川省成都市2023-2024學(xué)年高二上學(xué)期期末調(diào)研考試語(yǔ)文試題(解析版)
- ps經(jīng)典課程-海報(bào)設(shè)計(jì)(第六講)
- 江蘇省泰州市2023-2024學(xué)年高一上學(xué)期期末語(yǔ)文試題及答案
- 【MOOC】工程制圖解讀-西安交通大學(xué) 中國(guó)大學(xué)慕課MOOC答案
- 期末復(fù)習(xí)(試題)-2024-2025學(xué)年三年級(jí)上冊(cè)數(shù)學(xué)蘇教版
- 內(nèi)鏡中心年終總結(jié)和計(jì)劃
- 周五學(xué)習(xí)制度
評(píng)論
0/150
提交評(píng)論