進(jìn)程間通信管道和信號(hào)_第1頁(yè)
進(jìn)程間通信管道和信號(hào)_第2頁(yè)
進(jìn)程間通信管道和信號(hào)_第3頁(yè)
進(jìn)程間通信管道和信號(hào)_第4頁(yè)
進(jìn)程間通信管道和信號(hào)_第5頁(yè)
已閱讀5頁(yè),還剩69頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、進(jìn)程間通信進(jìn)程間通信PIPE 進(jìn)程間通信進(jìn)程間通信FIFO 信號(hào)中斷處理信號(hào)中斷處理 進(jìn)程間通信進(jìn)程間通信管道和信號(hào)管道和信號(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í)

2、控制進(jìn)程希望能夠攔截另一個(gè)進(jìn)程的所有陷入和異常,并能夠及時(shí)知道它的狀態(tài)改變。2022-3-162進(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ò)充,形成了“system V IPC”,通信進(jìn)程局限在單個(gè)計(jì)算機(jī)內(nèi);后者則跳過(guò)了該限制,形成了基于套接口(socket)的進(jìn)程間通信機(jī)制。Linux則把兩者繼承了下來(lái),其中,最初Unix IPC包括:管道、FIFO、

3、信號(hào);System V IPC包括:System V消息隊(duì)列、System V信號(hào)量、System V共享內(nèi)存區(qū);Posix IPC包括: Posix消息隊(duì)列、Posix信號(hào)量、Posix共享內(nèi)存區(qū)。2022-3-163Linux進(jìn)程通信方式linux下進(jìn)程間通信的幾種主要手段簡(jiǎn)介:1、管道(Pipe)及有名管道(named pipe):管道可用于具有親緣關(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)給

4、進(jìn)程本身;linux除了支持Unix早期信號(hào)語(yǔ)義函數(shù)signal外,還支持語(yǔ)義符合Posix.1標(biāo)準(zhǔn)的信號(hào)函數(shù)sigaction。2022-3-164Linux進(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)程可以訪(fǎng)問(wèn)同一塊內(nèi)存空間,是最快的可用IPC形式。是針對(duì)其他通信機(jī)制運(yùn)行效率較低而設(shè)計(jì)的。往往與其它通信機(jī)制,如信號(hào)量結(jié)合使用,來(lái)達(dá)到進(jìn)程間的同步及互斥。5、信號(hào)量(sema

5、phore):主要作為進(jìn)程間以及同一進(jìn)程不同線(xiàn)程之間的同步手段。2022-3-165管道管道的實(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(mǎn)時(shí),有一定的規(guī)則控制相應(yīng)的讀進(jìn)程或?qū)戇M(jìn)程是否進(jìn)入等待隊(duì)列;當(dāng)空的緩沖區(qū)有新數(shù)據(jù)寫(xiě)入或滿(mǎn)的緩沖區(qū)有數(shù)據(jù)讀出時(shí),就喚醒等待隊(duì)列中的進(jìn)程繼續(xù)讀寫(xiě)。2022-3-166管道管道實(shí)際上以類(lèi)似文件的方式與進(jìn)程交互,但它并不與磁盤(pán)打交道,所以效

6、率要比文件操作高很多。它有兩個(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è)置為EPIPE2022-3-167管道示例 例如$ ls | more功能是將ls命令的輸出作為more命令的輸入,并顯示more的最終輸出。這里ls與more要由兩個(gè)進(jìn)程來(lái)完成。這兩個(gè)進(jìn)程的通信就通過(guò)父進(jìn)程shell創(chuàng)建管道。ls向

7、管道輸入數(shù)據(jù),more從管道讀出數(shù)據(jù)。2022-3-168stdinstdinstdoutstdoutstderrstderrlsmore管 道 連 接 管道用于不同進(jìn)程間通信。通常先創(chuàng)建一個(gè)管道管道用于不同進(jìn)程間通信。通常先創(chuàng)建一個(gè)管道,再通過(guò),再通過(guò)forkfork函數(shù)創(chuàng)建一個(gè)子進(jìn)程,該子進(jìn)程會(huì)繼函數(shù)創(chuàng)建一個(gè)子進(jìn)程,該子進(jìn)程會(huì)繼承父進(jìn)程所創(chuàng)建的管道。承父進(jìn)程所創(chuàng)建的管道。創(chuàng)建無(wú)名管道 extern int pipe(int _pipedes2)此函數(shù)的參數(shù)是一個(gè)整型數(shù)組。如果執(zhí)行成功,pipe將存儲(chǔ)兩個(gè)整形文件描述符于_pipedes數(shù)組中,它們分別指向管道的兩端。如果系統(tǒng)調(diào)用失敗,將返回

8、-1。2022-3-1610注意:fd0 用于讀取管道,fd1 用于寫(xiě)入管道。圖1 linux中管道與文件描述符的關(guān)系#include #include #include #include int main()int pipe_fd2;if(pipe(pipe_fd)0)printf(pipe create errorn);return -1;else printf(pipe create successn);close(pipe_fd0);close(pipe_fd1);管道讀寫(xiě)管道主要用于不同進(jìn)程間通信。實(shí)際上,通常先創(chuàng)建一個(gè)管道,再通過(guò)fork函數(shù)創(chuàng)建一個(gè)子進(jìn)程。圖2 父子進(jìn)程管道的文件

9、描述符對(duì)應(yīng)關(guān)系子進(jìn)程寫(xiě)入和父進(jìn)程讀的命名管道:圖 關(guān)閉父進(jìn)程fd1 和子進(jìn)程fd0例:父子進(jìn)程通過(guò)無(wú)名管道通信#include #include #include #include #include #include main()pid_t result;int r_num;int pipe_fd2;char buf_r100,buf_w100; memset(buf_r,0,sizeof(buf_r);2022-3-1615例:父子進(jìn)程通過(guò)無(wú)名管道通信if(pipe(pipe_fd)0)perror(pipe);exit(EXIT_FAILURE); result=fork();if(res

10、ult0)printf(child process has read %d characters from the pipe,the string is:%sn,r_num,buf_r);close(pipe_fd0);exit(0);2022-3-1616例:父子進(jìn)程通過(guò)無(wú)名管道通信elseclose(pipe_fd0);printf(please input the string:);scanf(%s,buf_w);if(write(pipe_fd1,buf_w,strlen(buf_w)!=-1)printf(parent process has written:%s to the pi

11、pe!n,buf_w);close(pipe_fd1);waitpid(result,NULL,0);exit(0);2022-3-1617dup()extern int dup(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ǔ)句即可以將輸出重定向到管道:int f_des2;pipe(f_des);close(fileno(stdout);dup(f_des1)此后,所有寫(xiě)向標(biāo)準(zhǔn)輸出的數(shù)據(jù)

12、都將寫(xiě)入到管道中。因此,要復(fù)制標(biāo)準(zhǔn)輸出輸入設(shè)備,應(yīng)先關(guān)閉這一設(shè)備,然后再?gòu)?fù)制。2022-3-1618復(fù)制文件描述符 2022-3-1619dup2() extern int dup2(int _fd, int _fd2)dup2()有兩個(gè)參數(shù),fd和fd2,fd2是小于文件描述符的最大允許值的非負(fù)整數(shù)。如果fd2是一個(gè)已打開(kāi)的文件描述符,則首先關(guān)閉該文件,然后再?gòu)?fù)制。2022-3-1620綜合應(yīng)用舉例#include #include #include #include #include #define DEF_PAGER /bin/more“#define MAXLINE 10main(in

13、t argc,char * argv)int n;int fd2;pid_t pid;char *pager, *argv0;char lineMAXLINE;FILE *fp;2022-3-1621綜合應(yīng)用舉例if(argc!=2)printf(error usage!n);exit(EXIT_FAILURE); if(fp=fopen(argv1,r)=NULL)perror(open);exit(EXIT_FAILURE); if(pipe(fd)0) perror(pipe);exit(EXIT_FAILURE); if(pid=fork()0)close(fd0);while(fge

14、ts(line,MAXLINE,fp)!=NULL)n=strlen(line);if(write(fd1,line,n)!=n)perror(write);exit(EXIT_FAILURE);close(fd1);if(waitpid(pid,NULL,0)0)perror(wait);exit(EXIT_FAILURE);exit(0);2022-3-1623綜合應(yīng)用舉例elseclose(fd1);if(fd0!=STDIN_FILENO)if(dup2(fd0,STDIN_FILENO) != STDIN_FILENO)perror(dup);exit(EXIT_FAILURE);c

15、lose(fd0);if(pager=getenv(PAGER)=NULL)pager=DEF_PAGER;if(argv0=strrchr(pager,/)!=NULL) argv0+;elseargv0=pager;if(execl(pager,argv0,(char*)0)0)perror(exec);exit(EXIT_FAILURE);exit(0);2022-3-1624流重定向 extern FILE *popen(_const char * _command, _const char * _modes);popen 函數(shù)創(chuàng)建一個(gè)子進(jìn)程,并在子進(jìn)程中執(zhí)行第一個(gè)參數(shù)程序,同時(shí)返回一

16、個(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ù)聲明如下:extern int pclose(FILE * _stream);2022-3-1625例:流重定向的應(yīng)用#include /#include #include #include #include #define PAGER $PAGER:-

17、more“#define MAXLINE 10main(int argc, char *argv)char lineMAXLINE;FILE *fpin,*fpout;if(argc!=2)printf(error usage!n);exit(EXIT_FAILURE); 2022-3-1626例:流重定向的應(yīng)用if(fpin=fopen(argv1,r)=NULL)perror(open);exit(EXIT_FAILURE); if(fpout=popen(PAGER,w)=NULL)perror(popen);exit(EXIT_FAILURE); while(fgets(line,MA

18、XLINE,fpin)!=NULL)if(fputs(line,fpout)=EOF)perror(fputs);exit(EXIT_FAILURE);if(pclose(fpout)=-1)perror(pclose);exit(EXIT_FAILURE); exit(0);2022-3-1627注意事項(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ù)

19、據(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)程異常終止。2022-3-1628注意事項(xiàng):4. 如果有指向管道讀端的文件描述符沒(méi)有關(guān)閉,而持有管道讀端的進(jìn)程也沒(méi)有從管道中讀數(shù)據(jù),這時(shí)有進(jìn)程向管道寫(xiě)端寫(xiě)數(shù)據(jù),那么在管道被寫(xiě)滿(mǎn)時(shí)再次write會(huì)阻塞,直到管道中有空位置了才寫(xiě)入數(shù)據(jù)并返回。5. 兩個(gè)進(jìn)程通過(guò)一個(gè)管道只能實(shí)現(xiàn)單向通信,如果有時(shí)候也需要子進(jìn)程寫(xiě)父進(jìn)程讀,就必須另開(kāi)一個(gè)管道。2022-3-1629進(jìn)程間通信管道和信號(hào) 進(jìn)程間通信進(jìn)程間

20、通信PIPE 進(jìn)程間通信進(jìn)程間通信FIFO 信號(hào)中斷處理信號(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)的API open(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ú)讀者,那么

21、肯定是不能通信了,所以就需要先去睡眠等待讀者打開(kāi)該FIFO,反之對(duì)讀者亦然。2022-3-1631用途1.FIFO由shell命令使用以便將數(shù)據(jù)從一條管道線(xiàn)傳送到另一條,為此無(wú)需創(chuàng)建中間臨時(shí)文件。2.FIFO用于客戶(hù)進(jìn)程-服務(wù)器進(jìn)程應(yīng)用程序中,以在客戶(hù)進(jìn)程和服務(wù)器進(jìn)程之間傳遞數(shù)據(jù)。2022-3-1632創(chuàng)建FIFO/Create a new FIFO named PATH, with permission bits MODE. */extern int mkfifo(_comst char * _path, _mode_t _mode)mkfifo()會(huì)根據(jù)參數(shù)建立特殊的有名管道文件,該文件必

22、須不存在,而參數(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中。2022-3-1633例:命名管道的使用#include #include #include #include #include #define FIFO /tmp/fifo“main()pid_t pid;char buffer80;int fd;unlink(FIFO);mkfifo(FIFO,0744);2022-3-1634例:命名管道的使

23、用if(pid=fork()0)char s=Hello!;fd=open(FIFO,O_WRONLY);printf(this is father write data is %sn,s);printf(fathers pid is %dn,getpid();write(fd,s,sizeof(s);close(fd);exit(0);2022-3-1635例:命名管道的使用else if(pid=0)sleep(2);fd=open(FIFO,O_RDONLY);read(fd,buffer,80);printf(this is child read data is: %sn,buffer

24、);close(fd);printf(childs pid is %dn,getpid();exit(0);2022-3-1636管道基本特點(diǎn)總結(jié)兩類(lèi)型管道具有以下特點(diǎn):(1)管道是特殊類(lèi)型的文件,在滿(mǎn)足先入先出的原則條件下可能進(jìn)行讀寫(xiě),但不能定位讀寫(xiě)位置。(2)管道是單向的,要實(shí)現(xiàn)雙向,需要兩個(gè)管道。無(wú)名管道只能實(shí)現(xiàn)親緣關(guān)系進(jìn)程間通信(即無(wú)名管道的兩個(gè)文件描述符可以被兩者都訪(fǎng)問(wèn)到),而有名管道以磁盤(pán)文件的方式存在,可以實(shí)現(xiàn)本機(jī)任意兩進(jìn)程間通信。2022-3-1637管道基本特點(diǎn)總結(jié)(續(xù)) (3)無(wú)名管道阻塞問(wèn)題。無(wú)名管道無(wú)須顯式打開(kāi),創(chuàng)建時(shí)直接返回文件描述符,而在讀寫(xiě)時(shí)需要確實(shí)對(duì)方的存在,否

25、則將退出。即如果當(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)退出。2022-3-1638管道基本特點(diǎn)總結(jié)(續(xù)) (4)有名管道阻塞問(wèn)題。有名管道在打開(kāi)時(shí)需要確實(shí)對(duì)方的存在,否則將阻塞。即以讀方式打開(kāi)某管道,該操作得以繼續(xù)執(zhí)行的條件是:在此之前,已經(jīng)有一個(gè)進(jìn)程以寫(xiě)的方式打開(kāi)此管道,否則阻塞,直到條件滿(mǎn)足,因此有名管道將阻塞在打開(kāi)位置。也可以以讀寫(xiě)(ORDWR)方式打開(kāi)有名管道,進(jìn)程能夠繼續(xù)執(zhí)行(不阻塞),即當(dāng)前進(jìn)

26、程讀,當(dāng)前進(jìn)程寫(xiě)。2022-3-1639進(jìn)程間通信管道和信號(hào) 進(jìn)程間通信進(jìn)程間通信PIPE 進(jìn)程間通信進(jìn)程間通信FIFO 信號(hào)中斷處理信號(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ī)制除了基本通知功能外,還可以

27、傳遞附加信息。2022-3-1641Linux信號(hào)2022-3-1642/come from asm/signal.h常見(jiàn)的信號(hào)Linux系統(tǒng)中常見(jiàn)的信號(hào)說(shuō)明如下:1)SIGHUP:用戶(hù)從終端注銷(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ò)程中,用戶(hù)通過(guò)鍵盤(pán)按下【Ctrl】+【C】鍵將產(chǎn)生該信號(hào)。3)SIGQUIT:程序退出信號(hào)。在程序運(yùn)行過(guò)程中,用戶(hù)通過(guò)按下【Ctrl】+【】鍵將產(chǎn)生該信號(hào)。4)SIGBUS和SIGSEGV:進(jìn)程訪(fǎng)問(wèn)非法地址時(shí),引發(fā)該信號(hào)。5)SIGFPE:進(jìn)行算術(shù)運(yùn)算中出現(xiàn)致命錯(cuò)誤,如除

28、零操作、數(shù)據(jù)溢出等。2022-3-1643常見(jiàn)的信號(hào)(續(xù))6)SIGKILL:終止用戶(hù)進(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)程。2022-3-1644信號(hào)的分類(lèi)可靠信號(hào):也稱(chēng)為實(shí)時(shí)信號(hào),支持排隊(duì)。不可靠信號(hào):非實(shí)時(shí)信號(hào),不支持排隊(duì)。發(fā)送用戶(hù)進(jìn)程判斷后注冊(cè),發(fā)現(xiàn)相同信號(hào)已經(jīng)在進(jìn)程中注冊(cè),就不再注冊(cè),忽略該信號(hào)。2022-3-1

29、645可能的信號(hào)來(lái)源 信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,是一種異步通信方式。信號(hào)可以在用戶(hù)空間進(jìn)程和內(nèi)核之間直接交互,內(nèi)核也可以利用信號(hào)來(lái)通知用戶(hù)空間的進(jìn)程發(fā)生了哪些系統(tǒng)事件。信號(hào)事件的發(fā)生有兩個(gè)來(lái)源:1. 硬件來(lái)源:用戶(hù)按某些終端鍵時(shí)將產(chǎn)生信號(hào),如CTRL+C將產(chǎn)生SIGINT(中止信號(hào));硬件異常產(chǎn)生信號(hào),如除數(shù)為0或無(wú)效的存儲(chǔ)訪(fǎng)問(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)。2022-3-1646信號(hào)的處理流程 (1)信號(hào)被某個(gè)進(jìn)程產(chǎn)生,并設(shè)置此信號(hào)傳遞的對(duì)象(一般為對(duì)應(yīng)進(jìn)程的pid),然后傳遞給操作系統(tǒng);(2)操作系

30、統(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)度。 2022-3-1647信號(hào)的生命周期信號(hào)處理信號(hào)產(chǎn)生信號(hào)注冊(cè)信號(hào)注銷(xiāo)內(nèi)核進(jìn)

31、程用戶(hù)進(jìn)程2022-3-1648kill產(chǎn)生一個(gè)信號(hào) kill()函數(shù)用來(lái)向指定進(jìn)程發(fā)送一個(gè)信號(hào)。此函數(shù)聲明如下:/come from /usr/include/signal.hextern int kill (_pid_t _pid, int _sig)此函數(shù)的第一個(gè)參數(shù)為要傳遞信號(hào)的進(jìn)程號(hào)(PID),第二個(gè)參數(shù)即發(fā)送的信號(hào)值。 pid可以取以下幾種值:pido:將信號(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)程。pid0:將信號(hào)發(fā)送給進(jìn)程組號(hào)PGID為pid絕對(duì)值的所有進(jìn)程。如果成功完成返回值0,否

32、則返回-1,并設(shè)置errno以指示錯(cuò)誤。2022-3-1649#include #include void main(int argc,char *argv)int pid,signo;if(argc!=3)printf(usage: killsender pid signon);return;sscanf(argv1,%d,&pid); /獲取參數(shù)pidsscanf(argv2,%d,&signo); /獲取參數(shù)signoif(kill(pid,signo)0) /發(fā)送信號(hào)perror(kill);return;printf(ok: send out signal via kill syst

33、em call!n); 2022-3-1650例:編寫(xiě)程序例:編寫(xiě)程序killsender。通過(guò)。通過(guò)kill系統(tǒng)調(diào)用向指定進(jìn)系統(tǒng)調(diào)用向指定進(jìn)程(程(pid)發(fā)送信號(hào)。)發(fā)送信號(hào)。raise自舉一個(gè)信號(hào) raise()函數(shù)用來(lái)給當(dāng)前進(jìn)程發(fā)送一個(gè)信號(hào),即喚醒一個(gè)進(jìn)程。此函數(shù)聲明如下:/come from /usr/include/signal.h/*Raise signal SIG, i.e., send SIG to yourself. */extern int raise(int _sig)此函數(shù)相當(dāng)于采用以下方式執(zhí)行kill()函數(shù):if(kill(getpid(), int _sig)=

34、-1)perror(“raise”);2022-3-1651例:設(shè)計(jì)一個(gè)程序,創(chuàng)建一個(gè)子進(jìn)程,父進(jìn)程向子進(jìn)程發(fā)例:設(shè)計(jì)一個(gè)程序,創(chuàng)建一個(gè)子進(jìn)程,父進(jìn)程向子進(jìn)程發(fā)出信號(hào),子進(jìn)程收到此信號(hào),結(jié)束子進(jìn)程的運(yùn)行。出信號(hào),子進(jìn)程收到此信號(hào),結(jié)束子進(jìn)程的運(yùn)行。#include #include #include #include #include int main()pid_t result;int ret;result=fork();int newret;2022-3-1652if(result0)perror(fork);exit(EXIT_FAILURE);else if(result=0)rais

35、e(SIGSTOP);exit(0);elseprintf(childs pid=%dn,result);if(waitpid(result,NULL,WNOHANG)=0)if(ret=kill(result,SIGKILL)=0)printf(kill function finished %d process with return value=%dn,result,ret);elseperror(kill);2022-3-1653alarm()定時(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)。

36、/come from /usr/include/unistd.hextern unsigned int alarm(unsigned int _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ò)誤。2022-3-1654例:alarm的使用#include #include int main()printf(first time return

37、:%dn,alarm(4);sleep(1);printf(after sleep(1), remain:%dn,alarm(2);printf(renew alarm, remain:%dn,alarm(1);2022-3-1655ualarm定時(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_t ualarm(_useconds_t _value, _useconds_t _interval)2022-3-

38、1656信號(hào)處理與signal安裝信號(hào) 信號(hào)處理辦法 :(1)忽略此信號(hào)。忽略此信號(hào)。大多數(shù)信號(hào)都可使用這種方式進(jìn)行處理,但有兩種信號(hào)不能被忽略,SIGKILL和SIGSTOP。這兩種信號(hào)不能被忽略的原因是:它們向超級(jí)用戶(hù)提供一種使進(jìn)程終止或停止的可靠方法。(2)捕捉信號(hào)。捕捉信號(hào)。通知內(nèi)核在某種信號(hào)發(fā)生時(shí)調(diào)用一個(gè)用戶(hù)函數(shù)。在用戶(hù)函數(shù)中,可執(zhí)行用戶(hù)希望對(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)操作。執(zhí)行系統(tǒng)默認(rèn)操作。Linux系統(tǒng)對(duì)

39、任何一個(gè)信號(hào)都規(guī)定了一個(gè)默認(rèn)的操作。 2022-3-1657signal安裝信號(hào) typedef void(*_sighandler_t)(int );extern _sighander_t signal(int _sig, sighandler_t _handler)此函數(shù)有兩個(gè)參數(shù), 第一個(gè)參數(shù)sig為接收到的信號(hào),第二個(gè)參數(shù)為接收到此信號(hào)后的處理代碼入口或下面幾個(gè)宏:/* Fake signal functions. */#define SIG_ERR (_sighandler_t) -1) /*Error return. */#define SIG_DFL (_sighandler_t

40、) 0) /*Default action. */#define SIG_IGN (_sighandler_t) 1) /*Ignore signal. */2022-3-1658例:編寫(xiě)程序:killrecerver和killsender。其中killrecerver用于接收SIGUSR1(值為10)信號(hào),而killsender通過(guò)kill系統(tǒng)調(diào)用向指定進(jìn)程(pid)發(fā)送信號(hào)。#include #include #include #include /SIGUSR1信號(hào)處理函數(shù)void CbSigUsr1(int signo) /輸出接收到的信號(hào)信息printf(nreceive signal

41、=%d.n,signo);2022-3-1659void main()/安裝SIGUSR1信號(hào)if(signal(SIGUSR1,CbSigUsr1)=SIG_ERR)perror(signal);return;printf(my pid is %dn,getpid();printf(waiting for SIGUSR1.n);/暫停,等待信號(hào)pause();2022-3-1660例:signal的應(yīng)用#include #include #include #include void fun_ctrl_c();int main()(void)signal(SIGINT,fun_ctrl_c);

42、printf(Now Im starting.n);while(1)printf(this is an endless loop unless Ctrl+c are pressd!n);sleep(2);exit(0);2022-3-1661例:signal的應(yīng)用void fun_ctrl_c()printf(tCtrl+c were pressed!n);printf(t This is just an example for signal function!n);printf(treset signal SIGINTn);(void)signal(SIGINT,SIG_DFL);2022-

43、3-1662sigaction安裝信號(hào) extern int sigaction(int _sig, struct sigaction *_act, struct sigaction *_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)處理保持不變;因此,

44、該調(diào)用可用于詢(xún)問(wèn)對(duì)指定信號(hào)的當(dāng)前處理。2022-3-1663struct sigaction Struct sigactionunion_sighandler_t _sa_handler;void(*_sa_sigaction)(int , struct siginfo *, void *); _u;sigset_t sa_mask;unsigned long sa_flags;void(*sa_restorer)(void);#define sa_handler _u.sa_handler#define sa_sigaction _u._sa_sigaction2022-3-1664例:si

45、gaction的應(yīng)用#include #include #include void myhandler(int sig);int main()struct sigaction act,oact;act.sa_handler=myhandler;sigemptyset(&act.sa_mask);act.sa_flags=0;sigaction(SIGUSR1,&act,&oact);while(1)printf(hello world!n);pause();2022-3-1665void myhandler(int sig)printf(the signal %d was caught.n,s

46、ig);信號(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ā)生改變。2022-3-1666sigprocmask設(shè)置進(jìn)程阻塞的信號(hào)集 extern int sigprocmask(int _how, _const sigset_t * _restrict_set, sigset_t * _restrict_oset)此函數(shù)第一個(gè)參數(shù)為更改該集合的方式,如下所示:/come from /usr/include/asm/signal.h#define SIG_BLOCK 0 /*for blocking signals */#define SIG_UNBLOCK 1 /*for unblockin

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 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ì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論