版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
12進程間通信-PIPE
進程間通信―FIFO
3信號中斷處理
進程間通信——管道和信號進程通信有如下一些目的:
A、數(shù)據(jù)傳輸:一個進程需要將它的數(shù)據(jù)發(fā)送給另一個進程,發(fā)送的數(shù)據(jù)量在一個字節(jié)到幾M字節(jié)之間;
B、共享數(shù)據(jù):多個進程想要操作共享數(shù)據(jù),一個進程對共享數(shù)據(jù)的修改,別的進程應(yīng)該立刻看到;
C、通知事件:一個進程需要向另一個或一組進程發(fā)送消息,通知它(們)發(fā)生了某種事件(如進程終止時要通知父進程);
D、資源共享:多個進程之間共享同樣的資源。為了做到這一點,需要內(nèi)核提供鎖和同步機制;
E、進程控制:有些進程希望完全控制另一個進程的執(zhí)行(如Debug進程),此時控制進程希望能夠攔截另一個進程的所有陷入和異常,并能夠及時知道它的狀態(tài)改變。2023/2/12進程間通信的方式linux下的進程通信手段基本上是從Unix平臺上的進程通信手段繼承而來的。而對Unix發(fā)展做出重大貢獻的兩大主力AT&T的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟件發(fā)布中心)在進程間通信方面的側(cè)重點有所不同。前者對Unix早期的進程間通信手段進行了系統(tǒng)的改進和擴充,形成了“systemVIPC”,通信進程局限在單個計算機內(nèi);后者則跳過了該限制,形成了基于套接口(socket)的進程間通信機制。Linux則把兩者繼承了下來,其中,最初UnixIPC包括:管道、FIFO、信號;SystemVIPC包括:SystemV消息隊列、SystemV信號量、SystemV共享內(nèi)存區(qū);PosixIPC包括:Posix消息隊列、Posix信號量、Posix共享內(nèi)存區(qū)。2023/2/13Linux進程通信方式linux下進程間通信的幾種主要手段簡介:1、管道(Pipe)及有名管道(namedpipe):管道可用于具有親緣關(guān)系進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關(guān)系進程間的通信;2、信號(Signal):信號是比較復雜的通信方式,用于通知接受進程有某種事件發(fā)生,除了用于進程間通信外,進程還可以發(fā)送信號給進程本身;linux除了支持Unix早期信號語義函數(shù)signal外,還支持語義符合Posix.1標準的信號函數(shù)sigaction。2023/2/14Linux進程通信方式3、報文(Message)隊列(消息隊列):消息隊列是消息的鏈接表。有足夠權(quán)限的進程可以向隊列中添加消息,被賦予讀權(quán)限的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺點。4、共享內(nèi)存:使得多個進程可以訪問同一塊內(nèi)存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設(shè)計的。往往與其它通信機制,如信號量結(jié)合使用,來達到進程間的同步及互斥。5、信號量(semaphore):主要作為進程間以及同一進程不同線程之間的同步手段。2023/2/15管道管道的實質(zhì)是一個內(nèi)核緩沖區(qū),進程以先進先出的方式從緩沖區(qū)中存取數(shù)據(jù):管道一端的進程順序地將數(shù)據(jù)寫入緩沖區(qū),另一端的進程則順序地讀出數(shù)據(jù)。該緩沖區(qū)可以看作是一個循環(huán)隊列,讀和寫的位置都是自動增加的,不能隨意改變,一個數(shù)據(jù)只能被讀一次,讀出以后在緩沖區(qū)中就不復存在了。當緩沖區(qū)讀空或?qū)憹M時,有一定的規(guī)則控制相應(yīng)的讀進程或?qū)戇M程是否進入等待隊列;當空的緩沖區(qū)有新數(shù)據(jù)寫入或滿的緩沖區(qū)有數(shù)據(jù)讀出時,就喚醒等待隊列中的進程繼續(xù)讀寫。2023/2/16管道管道實際上以類似文件的方式與進程交互,但它并不與磁盤打交道,所以效率要比文件操作高很多。它有兩個局限性:(1)支持半雙工;(2)只有具有親緣關(guān)系的進程之間才能使用這種無名管道;使用管道的注意事項:1.當讀一個寫端已經(jīng)關(guān)閉的管道時,在所有數(shù)據(jù)被讀取之后,read函數(shù)返回值為0,以指示到了文件結(jié)束處;2.如果寫一個讀端關(guān)閉的管道,則產(chǎn)生SIGPIPE信號。如果忽略該信號或者捕捉該信號并處理程序返回,則write返回-1,errno設(shè)置為EPIPE2023/2/17管道示例例如$ls|more功能是將ls命令的輸出作為more命令的輸入,并顯示more的最終輸出。這里ls與more要由兩個進程來完成。這兩個進程的通信就通過父進程shell創(chuàng)建管道。ls向管道輸入數(shù)據(jù),more從管道讀出數(shù)據(jù)。2023/2/18stdinstdinstdoutstdoutstderrstderrlsmore管道連接管道用于不同進程間通信。通常先創(chuàng)建一個管道,再通過fork函數(shù)創(chuàng)建一個子進程,該子進程會繼承父進程所創(chuàng)建的管道。創(chuàng)建無名管道externintpipe(int__pipedes[2])此函數(shù)的參數(shù)是一個整型數(shù)組。如果執(zhí)行成功,pipe將存儲兩個整形文件描述符于__pipedes數(shù)組中,它們分別指向管道的兩端。如果系統(tǒng)調(diào)用失敗,將返回-1。2023/2/110注意:fd[0]用于讀取管道,fd[1]用于寫入管道。圖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]);}管道讀寫管道主要用于不同進程間通信。實際上,通常先創(chuàng)建一個管道,再通過fork函數(shù)創(chuàng)建一個子進程。圖2父子進程管道的文件描述符對應(yīng)關(guān)系子進程寫入和父進程讀的命名管道:圖
關(guān)閉父進程fd[1]和子進程fd[0]例:父子進程通過無名管道通信#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例:父子進程通過無名管道通信 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例:父子進程通過無名管道通信 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()會復制一份原來已經(jīng)打開的文件描述符,新的描述符指向系統(tǒng)文件表中下一個可用的最小非負文件描述符,它與原來的文件描述符共享同一個文件指針,并擁有相同的文件權(quán)限及模式。當調(diào)用dup()時,總返回下一個最小的可用文件描述符。例如:下面語句即可以將輸出重定向到管道:intf_des[2];pipe(f_des);close(fileno(stdout));dup(f_des[1])此后,所有寫向標準輸出的數(shù)據(jù)都將寫入到管道中。因此,要復制標準輸出輸入設(shè)備,應(yīng)先關(guān)閉這一設(shè)備,然后再復制。2023/2/118復制文件描述符2023/2/119dup2()externintdup2(int__fd,int__fd2)dup2()有兩個參數(shù),fd和fd2,fd2是小于文件描述符的最大允許值的非負整數(shù)。如果fd2是一個已打開的文件描述符,則首先關(guān)閉該文件,然后再復制。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)建一個子進程,并在子進程中執(zhí)行第一個參數(shù)程序,同時返回一個文件指針,即第一個參數(shù)*__command指向要執(zhí)行的命令的指針。第二個參數(shù)表示I/O模式的類型。如果此命令的輸出將作為其他命令的輸入,即輸出重定向,則需要設(shè)置其第二個參數(shù)為“r”權(quán)限;如果此命令的輸入數(shù)據(jù)要從其他命令的輸出數(shù)據(jù),即輸入重定向,則需要設(shè)置其第二個參數(shù)為“w”權(quán)限;在使用完重定向后,需要使用pclose()關(guān)閉相應(yīng)的流對象,該函數(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注意事項:1.如果所有指向管道寫端的文件描述符都關(guān)閉了,而仍然有進程從管道的讀端讀數(shù)據(jù),那么管道中剩余的數(shù)據(jù)都被讀取后,再次read會返回0,就像讀到文件末尾一樣。2.如果有指向管道寫端的文件描述符沒有關(guān)閉,而持有管道寫端的進程也沒有向管道中寫數(shù)據(jù),這時有進程從管道讀端讀數(shù)據(jù),那么管道中剩余的數(shù)據(jù)都被讀取后,再次read會阻塞,直到管道中有數(shù)據(jù)可讀了才讀取數(shù)據(jù)并返回。3.如果所有指向管道讀端的文件描述符都關(guān)閉了,這時有進程向管道的寫端write,那么該進程會收到信號SIGPIPE,通常會導致進程異常終止。2023/2/128注意事項:4.如果有指向管道讀端的文件描述符沒有關(guān)閉,而持有管道讀端的進程也沒有從管道中讀數(shù)據(jù),這時有進程向管道寫端寫數(shù)據(jù),那么在管道被寫滿時再次write會阻塞,直到管道中有空位置了才寫入數(shù)據(jù)并返回。5.兩個進程通過一個管道只能實現(xiàn)單向通信,如果有時候也需要子進程寫父進程讀,就必須另開一個管道。2023/2/129進程間通信-管道和信號12進程間通信-PIPE
進程間通信―FIFO
3信號中斷處理
FIFOFIFO就是命名管道,或有名管道。它同樣是基于VFS,對應(yīng)的文件類型就是FIFO文件,可以通過mknod命令在磁盤上創(chuàng)建一個FIFO文件。當進程想通過該FIFO來通信時就可以標準的APIopen(close、read、write、unlink等)打開該文件,然后開始讀寫操作。對于FIFO的讀寫實現(xiàn),它與pipe是相同的。區(qū)別在于,F(xiàn)IFO有open這一操作,而pipe是在調(diào)用pipe這個系統(tǒng)調(diào)用時直接創(chuàng)建了一對文件描述符用于通信。并且,F(xiàn)IFO的open操作還有些細致的地方要考慮,例如如果寫者先打開,尚無讀者,那么肯定是不能通信了,所以就需要先去睡眠等待讀者打開該FIFO,反之對讀者亦然。2023/2/131用途FIFO由shell命令使用以便將數(shù)據(jù)從一條管道線傳送到另一條,為此無需創(chuàng)建中間臨時文件。FIFO用于客戶進程-服務(wù)器進程應(yīng)用程序中,以在客戶進程和服務(wù)器進程之間傳遞數(shù)據(jù)。2023/2/132創(chuàng)建FIFO/CreateanewFIFOnamedPATH,withpermissionbitsMODE.*/externintmkfifo(__comstchar*__path,__mode_t__mode)mkfifo()會根據(jù)參數(shù)建立特殊的有名管道文件,該文件必須不存在,而參數(shù)mode為該文件的授權(quán),mkfifo()建立的FIFO文件其他進程都可以用讀寫一般文件的方式存取。當使用open()函數(shù)打開FIFO文件時,O_NONBLOCK會有影響。如果執(zhí)行成功將返回0,否則返回-1,失敗原因存儲于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管道基本特點總結(jié)兩類型管道具有以下特點:(1)管道是特殊類型的文件,在滿足先入先出的原則條件下可能進行讀寫,但不能定位讀寫位置。(2)管道是單向的,要實現(xiàn)雙向,需要兩個管道。無名管道只能實現(xiàn)親緣關(guān)系進程間通信(即無名管道的兩個文件描述符可以被兩者都訪問到),而有名管道以磁盤文件的方式存在,可以實現(xiàn)本機任意兩進程間通信。2023/2/137管道基本特點總結(jié)(續(xù))(3)無名管道阻塞問題。無名管道無須顯式打開,創(chuàng)建時直接返回文件描述符,而在讀寫時需要確實對方的存在,否則將退出。即如果當前進程向無名管道的一端寫數(shù)據(jù)時,必須確定其另一端為某個進程(這個進程可以是當前進程)擁有。如果寫入無名管道的數(shù)據(jù)超過其最大值,寫操作將阻塞,如果管道中沒有數(shù)據(jù),讀操作將阻塞,如果管道發(fā)現(xiàn)另一端斷開(另一端文件描述符關(guān)閉),將自動退出。2023/2/138管道基本特點總結(jié)(續(xù))(4)有名管道阻塞問題。有名管道在打開時需要確實對方的存在,否則將阻塞。即以讀方式打開某管道,該操作得以繼續(xù)執(zhí)行的條件是:在此之前,已經(jīng)有一個進程以寫的方式打開此管道,否則阻塞,直到條件滿足,因此有名管道將阻塞在打開位置。也可以以讀寫(O_RDWR)方式打開有名管道,進程能夠繼續(xù)執(zhí)行(不阻塞),即當前進程讀,當前進程寫。2023/2/139進程間通信-管道和信號12進程間通信-PIPE
進程間通信―FIFO
3信號中斷處理
信號概述信號是Linux系統(tǒng)中用于進程之間相互通信或操作的一種機制。信號可以在任何時候發(fā)給某一進程,而無需知道該進程的狀態(tài)。如果該進程當前并未處于執(zhí)行狀態(tài),則該信號就由內(nèi)核保存起來,直到該進程恢復執(zhí)行并傳遞給它為止;如果一個信號被進程設(shè)置為阻塞,則該信號的傳遞被延遲,直到其阻塞被取消時才被傳遞給進程。進程之間可以互相通過系統(tǒng)調(diào)用kill發(fā)送軟中斷信號。內(nèi)核也可以因為內(nèi)部事件而給進程發(fā)送信號,通知進程發(fā)生了某個事件。信號機制除了基本通知功能外,還可以傳遞附加信息。2023/2/141Linux信號2023/2/142//comefromasm/signal.h常見的信號Linux系統(tǒng)中常見的信號說明如下:1)SIGHUP:用戶從終端注銷時,所有已啟動的進程都將收到SIGHUP信號。系統(tǒng)缺省狀態(tài)下對該信號的處理就是中止進程。2)SIGINT:程序終止信號。在程序運行過程中,用戶通過鍵盤按下【Ctrl】+【C】鍵將產(chǎn)生該信號。3)SIGQUIT:程序退出信號。在程序運行過程中,用戶通過按下【Ctrl】+【\】鍵將產(chǎn)生該信號。4)SIGBUS和SIGSEGV:進程訪問非法地址時,引發(fā)該信號。5)SIGFPE:進行算術(shù)運算中出現(xiàn)致命錯誤,如除零操作、數(shù)據(jù)溢出等。2023/2/143常見的信號(續(xù))6)SIGKILL:終止用戶進程執(zhí)行的信號。在shell下通過執(zhí)行“kill-9”命令發(fā)送的就是該信號。7)SIGTERM:進程結(jié)束信號。在shell下執(zhí)行“kill進程pid”命令發(fā)送的就是該信號。8)SIGALRM:定時器信號。9)SIGCLD:子進程退出信號。如果父進程沒有忽略該信號,也沒有處理該信號,則子進程退出后將形成僵尸進程。2023/2/144信號的分類可靠信號:也稱為實時信號,支持排隊。不可靠信號:非實時信號,不支持排隊。發(fā)送用戶進程判斷后注冊,發(fā)現(xiàn)相同信號已經(jīng)在進程中注冊,就不再注冊,忽略該信號。2023/2/145可能的信號來源信號是在軟件層次上對中斷機制的一種模擬,是一種異步通信方式。信號可以在用戶空間進程和內(nèi)核之間直接交互,內(nèi)核也可以利用信號來通知用戶空間的進程發(fā)生了哪些系統(tǒng)事件。信號事件的發(fā)生有兩個來源:1.硬件來源:用戶按某些終端鍵時將產(chǎn)生信號,如CTRL+C將產(chǎn)生SIGINT(中止信號);硬件異常產(chǎn)生信號,如除數(shù)為0或無效的存儲訪問等。2.軟件來源:終止進程信號,其他進程調(diào)用kill函數(shù),將信號發(fā)送個另一個進程或進程組;軟件異常產(chǎn)生信號。2023/2/146信號的處理流程(1)信號被某個進程產(chǎn)生,并設(shè)置此信號傳遞的對象(一般為對應(yīng)進程的pid),然后傳遞給操作系統(tǒng);(2)操作系統(tǒng)根據(jù)接收進程的設(shè)置(是否阻塞)而選擇性的發(fā)送給接收者,如果接收者阻塞該信號(且該信號是可以阻塞的),操作系統(tǒng)將暫時保留該信號,而不傳遞,直到該進程解除對此信號的阻塞(如果對應(yīng)進程已經(jīng)退出,則丟棄此信號);如果對應(yīng)進程沒有阻塞,操作系統(tǒng)將傳遞此信號;(3)目的進程接收到此信號后,將根據(jù)當前進程對此信號設(shè)置的預處理方式,暫時終止當前代碼的執(zhí)行,保護上下文(主要包括臨時寄存器數(shù)據(jù)、當前程序位置以及當前CPU的狀態(tài))、轉(zhuǎn)而執(zhí)行中斷服務(wù)程序,執(zhí)行完成后再恢復到被中斷的位置。當然,對于可搶占式內(nèi)核,在中斷返回時還將引發(fā)新的調(diào)度。2023/2/147信號的生命周期信號處理信號產(chǎn)生信號注冊信號注銷內(nèi)核進程用戶進程2023/2/148kill產(chǎn)生一個信號kill()函數(shù)用來向指定進程發(fā)送一個信號。此函數(shù)聲明如下://comefrom/usr/include/signal.hexternintkill(__pid_t__pid,int__sig)此函數(shù)的第一個參數(shù)為要傳遞信號的進程號(PID),第二個參數(shù)即發(fā)送的信號值。pid可以取以下幾種值:pid>o:將信號發(fā)送給進程的PID值為pid的進程。pid=0:將信號發(fā)送給和當前進程在同一進程組的所有進程。pid=-1:將信號發(fā)送給系統(tǒng)內(nèi)的所有進程。pid<0:將信號發(fā)送給進程組號PGID為pid絕對值的所有進程。如果成功完成返回值0,否則返回-1,并設(shè)置errno以指示錯誤。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ā)送信號 perror("kill"); return; } printf("ok:sendoutsignalviakillsystemcall!\n");}2023/2/150例:編寫程序killsender。通過kill系統(tǒng)調(diào)用向指定進程(pid)發(fā)送信號。raise自舉一個信號raise()函數(shù)用來給當前進程發(fā)送一個信號,即喚醒一個進程。此函數(shù)聲明如下://comefrom/usr/include/signal.h/*RaisesignalSIG,i.e.,sendSIGtoyourself.*/externintraise(int__sig)此函數(shù)相當于采用以下方式執(zhí)行kill()函數(shù):if(kill(getpid(),int__sig)==-1)
perror(“raise”);2023/2/151例:設(shè)計一個程序,創(chuàng)建一個子進程,父進程向子進程發(fā)出信號,子進程收到此信號,結(jié)束子進程的運行。#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()定時alarm()函數(shù)用來傳遞定時信號,即在多少時間內(nèi)產(chǎn)生SIGALRM信號,此函數(shù)每調(diào)用一次,產(chǎn)生一個信號,并不是循環(huán)產(chǎn)生SIGALRM信號。//comefrom/usr/include/unistd.hexternunsignedintalarm(unsignedint__seconds)此函數(shù)只有一個參數(shù),即在多少時間(秒)內(nèi)發(fā)送SIGALRM信號給當前進程,默認情況下,當進程接受到alarm信號后將終止執(zhí)行;如果sec為0,則取消所有先前發(fā)出的報警請求。如果在調(diào)用alarm()函數(shù)前沒有調(diào)用過alarm()函數(shù),如果執(zhí)行成功,將返回0,否則返回-1,并置errno標致錯誤。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定時ualarm將使當前進程在指定時間(第一個參數(shù),以us為單位)內(nèi)產(chǎn)生SIGALRM信號,然后每隔指定時間(第二個參數(shù),以us為單位)重復產(chǎn)生SIGALRM信號。如果執(zhí)行成功將返回0,該函數(shù)聲明如下:extern__useconds_tualarm(__useconds_t__value,__useconds_t__interval)2023/2/156信號處理與signal安裝信號信號處理辦法:(1)忽略此信號。大多數(shù)信號都可使用這種方式進行處理,但有兩種信號不能被忽略,SIGKILL和SIGSTOP。這兩種信號不能被忽略的原因是:它們向超級用戶提供一種使進程終止或停止的可靠方法。(2)捕捉信號。通知內(nèi)核在某種信號發(fā)生時調(diào)用一個用戶函數(shù)。在用戶函數(shù)中,可執(zhí)行用戶希望對這種事件進行的處理,這需要安裝此信號。例如捕捉到SIGCHLD信號,則表示子進程已經(jīng)終止,所以此信號的捕捉函數(shù)可以調(diào)用waitpid()以取得該子進程的進程PID以及它的終止狀態(tài)和資源。(3)執(zhí)行系統(tǒng)默認操作。Linux系統(tǒng)對任何一個信號都規(guī)定了一個默認的操作。2023/2/157signal安裝信號typedefvoid(*__sighandler_t)(int);extern__sighander_tsignal(int__sig,sighandler_t__handler)此函數(shù)有兩個參數(shù),第一個參數(shù)sig為接收到的信號,第二個參數(shù)為接收到此信號后的處理代碼入口或下面幾個宏:/*Fakesignalfunctions.*/#defineSIG_ERR((__sighandler_t)-1)/*Errorreturn.*/#defineSIG_DFL((__sighandler_t)0)/*Defaultaction.*/#defineSIG_IGN((__sighandler_t)1)/*Ignoresignal.*/2023/2/158例:編寫程序:killrecerver和killsender。其中killrecerver用于接收SIGUSR1(值為10)信號,而killsender通過kill系統(tǒng)調(diào)用向指定進程(pid)發(fā)送信號。#include<stdio.h>#include<unistd.h>#include<sys/types.h>#include<signal.h>//SIGUSR1信號處理函數(shù)voidCbSigUsr1(intsigno){//輸出接收到的信號信息 printf("\nreceivesignal=%d.\n",signo);}2023/2/159voidmain() {//安裝SIGUSR1信號 if(signal(SIGUSR1,CbSigUsr1)==SIG_ERR){ perror("signal"); return;} printf("mypidis%d\n",getpid()); printf("waitingforSIGUSR1...\n");//暫停,等待信號 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安裝信號externintsigaction(int__sig,structsigaction*__act,structsigaction*__oact)此函數(shù)的第一個參數(shù)為接收到的信號,第二、三個參數(shù)均為信號結(jié)構(gòu)sigaction(用于描述要采取的操作及相關(guān)信息,見后續(xù)說明)變量。第二個參數(shù)用來指定欲設(shè)置的信號處理信息,第三個參數(shù)將返回執(zhí)行此程序前信號處理信息。如果第二個參數(shù)act不為空指針,則指定信號關(guān)聯(lián)的操作為此參數(shù)指向的結(jié)構(gòu)。如果參數(shù)oact不為空指針,則用來存儲以前設(shè)置的與此信號關(guān)聯(lián)的操作。如果參數(shù)act為空指針,則信號處理保持不變;因此,該調(diào)用可用于詢問對指定信號的當前處理。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);}信號集與屏蔽信號中斷是可以被屏蔽(阻塞)的(部分硬件中斷是必須立即處理的,例如復位中斷),因此,Linux的信號是可以屏蔽,即阻塞信號。但這與前面提到的忽略是有區(qū)別的。信號忽略:系統(tǒng)仍然傳遞該信號,只是相應(yīng)進程對該信號不作任何處理而已。信號阻塞:系統(tǒng)不傳遞該信號,顯示該進程無法接收到該信號直到進程的信號集發(fā)生改變。2023/2/166sigprocmask設(shè)置進程阻塞的信號集externintsigprocmask(int__how,__constsigset_t*__restrict__set,sigset_t*__restrict__oset)此函數(shù)第一個參數(shù)為更改該集合的方式,如下所示://comefrom/usr/include/asm/signal.h#defineSIG_BLOCK0/*forblockingsignals*/#defineSIG_UNBLOCK1
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年平陽縣中醫(yī)院招聘體檢中心導檢人員備考題庫及完整答案詳解一套
- 普洱市第一中學2026年度急需緊缺人才第二批招聘備考題庫及一套參考答案詳解
- 2025年貴州望謨縣消防救援大隊面向社會公開招聘政府專職消防隊伍隊員25人備考題庫及答案詳解一套
- 2025年湛江市國核湛江核電有限公司社會招聘33人備考題庫及答案詳解1套
- 2025年資陽市婦女聯(lián)合會公開招聘社會化工作者的備考題庫及1套參考答案詳解
- 2025年寧波市教育局直屬學校教師招聘58人備考題庫及1套完整答案詳解
- 2025廣西百色市西林縣機關(guān)后勤服務(wù)中心招聘編外聘用人員3人備考考試試題及答案解析
- 2025江蘇蘇州高新區(qū)獅山街道農(nóng)村社區(qū)股份合作聯(lián)社招聘2人筆試備考重點試題及答案解析
- 2025年未央?yún)^(qū)大明宮社區(qū)衛(wèi)生服務(wù)中心中醫(yī)科招聘康復治療師、中醫(yī)醫(yī)師各1名備考題庫有答案詳解
- 安鋼總醫(yī)院2026年度招聘備考題庫參考答案詳解
- 頸椎病的手術(shù)治療方法
- 野性的呼喚讀書分享
- 極簡化改造實施規(guī)范
- 科研方法論智慧樹知到期末考試答案章節(jié)答案2024年南開大學
- DBJ51-T 139-2020 四川省玻璃幕墻工程技術(shù)標準
- 一帶一路教學課件教學講義
- 工廠蟲害控制分析總結(jié)報告
- 回顧性中醫(yī)醫(yī)術(shù)實踐資料(醫(yī)案)表
- 延期交房起訴狀
- 廣東省消防安全重點單位消防檔案
- 高考日語形式名詞わけ、べき、はず辨析課件
評論
0/150
提交評論