版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第7章進(jìn)程間的通信2本章重點(diǎn)進(jìn)程通信中信號(hào)概念及信號(hào)處理進(jìn)程間的管道通信編程進(jìn)程間的內(nèi)存共享編程3Linux中進(jìn)程間通信(IPC)概述**管道、FIFO、信號(hào)、消息隊(duì)列、信號(hào)燈、共享內(nèi)存共享內(nèi)存進(jìn)程1進(jìn)程2管道pipesignal消息隊(duì)列4Linux中進(jìn)程間通信概述**管道(Pipe)及有名管道(namedpipe)
管道是一種在進(jìn)程之間單向流動(dòng)數(shù)據(jù)的結(jié)構(gòu)。源進(jìn)程向管道寫(xiě)數(shù)據(jù),而內(nèi)核會(huì)自動(dòng)將這些數(shù)據(jù)引導(dǎo)向目標(biāo)進(jìn)程。
管道:用于具有親緣關(guān)系的進(jìn)程間的通信有名管道:除具有管道所具有的功能外,還允許無(wú)親緣關(guān)系的進(jìn)程間的通信5Linux中進(jìn)程間通信概述**Linux系統(tǒng)信號(hào)(signal)
信號(hào)主要用于通知進(jìn)程異步事件的發(fā)生。 在Linux中可以識(shí)別29種不同的信號(hào),這些信號(hào)中的大部分都有了預(yù)先定義好的意義。6Linux中進(jìn)程間通信概述**消息隊(duì)列消息隊(duì)列是由內(nèi)核創(chuàng)建并維護(hù)的一個(gè)數(shù)據(jù)結(jié)構(gòu),它是有標(biāo)識(shí)的。任何具有足夠權(quán)限的進(jìn)程都可以向消息隊(duì)列中放置一個(gè)消息,同樣,任何具有足夠權(quán)限的進(jìn)程都可以從中讀取一個(gè)消息。不同的進(jìn)程通過(guò)訪問(wèn)相同的消息隊(duì)列便可實(shí)現(xiàn)進(jìn)程間通信。7Linux中進(jìn)程間通信概述**共享內(nèi)存共享內(nèi)存區(qū)是這幾種進(jìn)程間通信方式中最快的一種。它的特點(diǎn)除了速度快外,而且可傳遞的信息量大。通過(guò)將一段內(nèi)存區(qū)映射到一個(gè)進(jìn)程的地址空間來(lái)實(shí)現(xiàn)。因此,這種進(jìn)程間通信就不再涉及到內(nèi)核(即進(jìn)程不是通過(guò)執(zhí)行任何進(jìn)入內(nèi)核的系統(tǒng)調(diào)用來(lái)傳遞數(shù)據(jù)的。內(nèi)核必須建立允許各個(gè)進(jìn)程共享該內(nèi)存區(qū)的內(nèi)存映射關(guān)系,然后一直管理該內(nèi)存區(qū))。但同時(shí),也要有效地保證它能同步、有序且沒(méi)有死鎖。8Linux中進(jìn)程間通信概述**信號(hào)量信號(hào)量并不是一種IPC機(jī)制,它是用于提供不同進(jìn)程間或一給定進(jìn)程的不同線程間同步的一種手段。97.1.1信號(hào)及其使用
信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,是一種異步通信方式。信號(hào)可以直接進(jìn)行用戶空間進(jìn)程和內(nèi)核進(jìn)程之間的交互,內(nèi)核進(jìn)程也可以利用它來(lái)通知用戶空間進(jìn)程發(fā)生了哪些系統(tǒng)事件。信號(hào)主要用于通知進(jìn)程異步事件的發(fā)生。在Linux中可以識(shí)別29種不同的信號(hào),這些信號(hào)中的大部分都有了預(yù)先定義好的意義。107.1.1信號(hào)及其使用信號(hào)事件的發(fā)生有兩個(gè)來(lái)源:硬件來(lái)源,如按下了鍵盤(pán)Delete鍵或者鼠標(biāo)單擊,通常產(chǎn)生中斷信號(hào)(SIGINT)或者其它硬件故障。軟件來(lái)源,如使用系統(tǒng)調(diào)用或者是命令發(fā)出信號(hào)。最常用發(fā)送信號(hào)的系統(tǒng)函數(shù)是kill、raise、alarm、setitimer、sigation和sigqueue函數(shù),軟件來(lái)源還包括一些非法運(yùn)算等操作。117.1.1信號(hào)及其使用**一旦有信號(hào)產(chǎn)生,用戶進(jìn)程對(duì)信號(hào)的響應(yīng)有3種方式:執(zhí)行默認(rèn)操作。Linux對(duì)每種信號(hào)都規(guī)定了默認(rèn)操作。捕捉信號(hào)。定義信號(hào)處理函數(shù),當(dāng)信號(hào)發(fā)生時(shí),執(zhí)行相應(yīng)的處理函數(shù)。忽略信號(hào)。不希望接收到的信號(hào)對(duì)進(jìn)程的執(zhí)行產(chǎn)生影響,而讓進(jìn)程繼續(xù)進(jìn)行時(shí),可以忽略該信號(hào),即不對(duì)信號(hào)進(jìn)程任何處理。12信號(hào)與信號(hào)處理**進(jìn)程A信號(hào)產(chǎn)生進(jìn)程B信號(hào)處理(信號(hào)接收)13常見(jiàn)信號(hào)的含義及其默認(rèn)操作*14信號(hào)處理常用函數(shù)**發(fā)送信號(hào)函數(shù)Kill(pid_tpid,sig);給指定的進(jìn)程發(fā)送信號(hào)。raise(intsig);給當(dāng)前進(jìn)程發(fā)送信號(hào)。Alarm(unsignedintseconds);給當(dāng)前進(jìn)程發(fā)送時(shí)鐘報(bào)警信號(hào)。pause(void);等待信號(hào)到來(lái)處理信號(hào)函數(shù)-信號(hào)捕捉Signal(sig,voidsigfunc(int));信號(hào)處理15信號(hào)處理常見(jiàn)函數(shù)信號(hào)發(fā)送函數(shù)(1)***
#include<sys/types.h>
#include<signal.h>
intkill(pid_tpid,intsig);
說(shuō)明:
kill()可以用來(lái)送參數(shù)sig指定的信號(hào)給參數(shù)pid指定的進(jìn)程。
參數(shù)pid有幾種情況:
pid>0將信號(hào)傳給進(jìn)程識(shí)別碼為pid的進(jìn)程。
pid=0將信號(hào)傳給和目前進(jìn)程相同進(jìn)程組的所有進(jìn)程
pid=-1將信號(hào)廣播傳送給系統(tǒng)內(nèi)所有的進(jìn)程
返回值: 成功:返回0,錯(cuò)誤:返回-1。
16信號(hào)處理常見(jiàn)函數(shù)//范例**#include<unistd.h>#include<signal.h>#include<sys/types.h>#include<sys/wait.h>intmain(){ pid_tpid; intstatus; if(!(pid=fork())){ printf(“HiIamchildprocess!\n”); sleep(10); return; } else{ printf(“sendsignaltochildprocess(%d)\n”,pid); sleep(1); kill(pid,SIGKILL); wait(&status); }}
17信號(hào)處理常見(jiàn)
函數(shù)信號(hào)發(fā)送函數(shù)(2)***函數(shù)格式
#include<unistd.h>
定義函數(shù)unsignedintalarm(unsignedintseconds);函數(shù)說(shuō)明
alarm()用來(lái)設(shè)置信號(hào)SIGALRM在經(jīng)過(guò)參數(shù)seconds指定的秒數(shù)后傳送給目前的進(jìn)程。參數(shù) 若seconds=0,則之前設(shè)置的鬧鐘會(huì)被取消,并將剩下的時(shí)間返回。返回值 返回之前鬧鐘的剩余秒數(shù),如果之前未設(shè)鬧鐘則返回0。18//范例2***#include<unistd.h>#include<signal.h>voidhandler(){ printf(“hello\n”);}intmain(){ inti; signal(SIGALRM,handler); alarm(5); for(i=1;i<7;i++){ printf(“sleep%d...\n”,i); sleep(1); }}
19信號(hào)處理常見(jiàn)函數(shù)信號(hào)捕獲函數(shù)(1)***
#include<signal.h>
void(*signal(intsignum,void(*handler)(int)))(int);
voidsignal(int信號(hào)名,信號(hào)處理函數(shù)名)信號(hào)處理函數(shù)void函數(shù)名(int信號(hào)名)函數(shù)說(shuō)明
signal()會(huì)依參數(shù)signum指定的信號(hào)編號(hào)來(lái)設(shè)置該信號(hào)的處理函數(shù)。當(dāng)指定的信號(hào)到達(dá)時(shí)就會(huì)跳轉(zhuǎn)到參數(shù)handler指定的函數(shù)執(zhí)行。
20//范例***
#include<unistd.h>#include<signal.h>voidhandler(){ printf(“hello\n”);}intmain(){ inti; signal(SIGALRM,handler); alarm(5); for(i=1;i<7;i++){ printf(“sleep%d...\n”,i); sleep(1); }}21#include<signal.h>#include<sys/wait.h>#include<stdio.h>#include<stdlib.h>#include<unistd.h>voidoutDate(intn);voidexitProc(intn);intexitSig=0;intmain(){
(void)signal(SIGALRM,outDate); (void)signal(SIGINT,exitProc); while(1){ alarm(1); /*時(shí)鐘報(bào)警函數(shù)*/ pause(); if(exitSig) exit(0); }}/*************
SIGALRM信號(hào)處理函數(shù)*************/voidoutDate(intn){ system("date&");/*執(zhí)行外部命令 */}/*************
SIGINT信號(hào)處理函數(shù)*************/voidexitProc(intn){ printf("Ctrl_C\n"); exitSig=1;}例:信號(hào)的捕捉***227.2.1信號(hào)操作的相關(guān)函數(shù)***237.2.1信號(hào)操作的相關(guān)函數(shù)24信號(hào)操作小結(jié)信號(hào)信號(hào)的發(fā)送信號(hào)的捕捉及處理信號(hào)的忽略、阻塞25信號(hào)操作小結(jié)信號(hào)26信號(hào)操作小結(jié)信號(hào)的發(fā)送Kill(pid_tpid,sig);給指定的進(jìn)程發(fā)送信號(hào)。raise(intsig);給當(dāng)前進(jìn)程發(fā)送信號(hào)。Alarm(unsignedintseconds);給當(dāng)前進(jìn)程發(fā)送時(shí)鐘報(bào)警信號(hào)。pause(void);等待信號(hào)到來(lái)27信號(hào)操作小結(jié)信號(hào)的捕捉及處理Signal(sig,voidsigfunc(int));信號(hào)處理28信號(hào)的忽略與阻塞信號(hào)的忽略Signal()選項(xiàng):29信號(hào)的忽略與阻塞信號(hào)的阻塞有時(shí)既不希望進(jìn)程在接收到信號(hào)時(shí)立刻中斷進(jìn)程的執(zhí)行,也不希望此信號(hào)完全被忽略掉,而是延遲一段時(shí)間再去調(diào)用信號(hào)處理函數(shù),這個(gè)時(shí)候就需要信號(hào)阻塞來(lái)完成。步驟清空待處理的信號(hào)集追加待處理信號(hào)到信號(hào)集設(shè)置/解除信號(hào)掩碼(設(shè)置屏蔽)307.2.1信號(hào)操作的相關(guān)函數(shù)§317.2.1信號(hào)操作的相關(guān)函數(shù)327.2.1信號(hào)操作的相關(guān)函數(shù)33信號(hào)操作小結(jié)信號(hào)的忽略、阻塞*信號(hào)的忽略Signal(sig,voidsigfunc(int));選項(xiàng)(第2個(gè)參數(shù))SIG_IGN:忽略指定的信號(hào)SIG_DFL:信號(hào)處理方式重新設(shè)為內(nèi)核預(yù)設(shè)方式阻塞步驟清空待處理的信號(hào)集:sigempty()追加待處理信號(hào)到信號(hào)集:sigaddset()設(shè)置/解除信號(hào)掩碼(設(shè)置屏蔽):sigprocmask()347.2管道**無(wú)名管道(PIPE)有名管道(FIFO)進(jìn)程x進(jìn)程y管道pipe357.2管道**在Linux系統(tǒng)中,管道用于兩個(gè)進(jìn)程間的通信,這兩個(gè)進(jìn)程要有同源性,即它們必須是最終由同一個(gè)進(jìn)程所生成的進(jìn)程。管道通信采用的是半雙工方式,即同一時(shí)間只允許單方向傳輸數(shù)據(jù)。進(jìn)程x進(jìn)程y管道pipe367.2管道**在Linux中,管道是一種特殊的文件,對(duì)一個(gè)進(jìn)程來(lái)說(shuō),管道的寫(xiě)入和讀取與一個(gè)普通文件沒(méi)有區(qū)別。管道是Linux支持的最初UnixIPC形式之一,具有以下特點(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),而是自立門(mén)戶,單獨(dú)構(gòu)成一種文件系統(tǒng),并且只存在與內(nèi)存中。37管道***387.2.1無(wú)名管道操作無(wú)名管道操作時(shí),建立管道用pipe函數(shù)建立管道后Linux系統(tǒng)會(huì)同時(shí)為該進(jìn)程建立2個(gè)文件描述符pipe_fd[0]和pipe_fd[1]。pipe_fd[0]用來(lái)從管道讀取數(shù)據(jù)pipe_fd[1]用來(lái)把數(shù)據(jù)寫(xiě)入管道39無(wú)名管道操作**40無(wú)名管道操作步驟**創(chuàng)建管道創(chuàng)建進(jìn)程讀/寫(xiě)寫(xiě)進(jìn)程關(guān)閉管道的讀端讀進(jìn)程關(guān)閉管道的寫(xiě)端無(wú)名管道操作讀管道進(jìn)程的有關(guān)規(guī)則如果進(jìn)程讀一個(gè)寫(xiě)端關(guān)閉的管道read()返回0,表示結(jié)束。如果進(jìn)程讀一個(gè)寫(xiě)端仍打開(kāi)的空管道該進(jìn)程休眠,直到管道中有新的輸入。如果進(jìn)程試圖從管道中讀多于現(xiàn)有的字節(jié)返回當(dāng)前的所有內(nèi)容,read()返回實(shí)際讀取的字節(jié)。寫(xiě)端讀端fd[0]fd[1]無(wú)名管道操作寫(xiě)管道進(jìn)程的有關(guān)規(guī)則如果進(jìn)程寫(xiě)一個(gè)讀端關(guān)閉的管道寫(xiě)操作失敗,將一個(gè)SIGPIPE信號(hào)發(fā)送給寫(xiě)進(jìn)程。缺省操作為終止進(jìn)程。如果進(jìn)程寫(xiě)入管道的字節(jié)數(shù)少于管道能保存的數(shù)write()保證是原子操作,即寫(xiě)進(jìn)程將完成它的系統(tǒng)調(diào)用,不會(huì)被另一個(gè)進(jìn)程搶占。寫(xiě)端讀端fd[0]fd[1]43管道的局限性*
管道的主要局限性正體現(xiàn)在它的特點(diǎn)上:只支持單向數(shù)據(jù)流;只能用于具有親緣關(guān)系的進(jìn)程之間;沒(méi)有名字;管道的緩沖區(qū)是有限的(管道制存在于內(nèi)存中,在管道創(chuàng)建時(shí),為緩沖區(qū)分配一個(gè)頁(yè)面大?。?;管道所傳送的是無(wú)格式字節(jié)流,這就要求管道的讀出方和寫(xiě)入方必須事先約定好數(shù)據(jù)的格式,比如多少字節(jié)算作一個(gè)消息(或命令、或記錄)等等;44范例***/*父進(jìn)程借管道將字符串“hello!\n”傳給子進(jìn)程并顯示*/#include<unistd.h>intmain(){ intfiledes[2]; charbuffer[80]; pipe(filedes); if(fork()>0){ /*父進(jìn)程*/ chars[]=“hello!\n”; write(filedes[1],s,sizeof(s)); } else{ /*子進(jìn)程*/ read(filedes[0],buffer,80); printf(“%s”,buffer); } exit(0);}457.2.1無(wú)名管道操作例7.5***:設(shè)計(jì)一個(gè)程序,要求創(chuàng)建一個(gè)管道,父進(jìn)程往管道中寫(xiě)入字符串,子進(jìn)程從管道中讀取前輸出字符串。源程序代碼:487.2.1無(wú)名管道操作**497.2.3命名管道*若要在兩個(gè)不相關(guān)的進(jìn)程之間用管道通信,需要用到命名管道FIFO。命名管道FIFO是通過(guò)Linux系統(tǒng)中的文件進(jìn)行通信。命名管道的創(chuàng)建一般用mkfifo函數(shù),創(chuàng)建成功后,就使用open、read、write等函數(shù)傳輸數(shù)據(jù)。有名管道FIFO不同于管道之處在于它提供一個(gè)路徑名與之關(guān)聯(lián),以FIFO的文件形式存在于文件系統(tǒng)中。FIFO嚴(yán)格遵循先進(jìn)先出(firstinfirstout),對(duì)管道及FIFO的讀總是從開(kāi)始處返回?cái)?shù)據(jù),對(duì)它們的寫(xiě)則把數(shù)據(jù)添加到末尾。50有名管道的操作步驟**創(chuàng)建(僅創(chuàng)建一次)~mkfifo()打開(kāi)(以阻塞形式)~open()省略~阻塞O_NONBLOCK~非阻塞讀/寫(xiě)~read()/write()關(guān)閉~close()517.2.3命名管道**mkfifo函數(shù)說(shuō)明說(shuō)明:如果mkfifo的第一個(gè)參數(shù)是一個(gè)已經(jīng)存在的路徑名時(shí),會(huì)返回EEXIST錯(cuò)誤,所以一般典型的調(diào)用代碼首先會(huì)檢查是否返回該錯(cuò)誤,如果確實(shí)返回該錯(cuò)誤,那么只要調(diào)用打開(kāi)FIFO的函數(shù)就可以了。一般文件的I/O函數(shù)都可以用于FIFO,如close、read、write等等。52PGO所有者用戶組其他用戶組RWX讀寫(xiě)執(zhí)行
0000101001101110:無(wú)任何權(quán)限2:只寫(xiě)4:只讀6:可讀可寫(xiě)7:可讀可寫(xiě)可執(zhí)行文件權(quán)限說(shuō)明*文件權(quán)限由3位8進(jìn)制數(shù)表示,分別代表:掩碼:訪問(wèn)權(quán)限位的屏蔽字與文件訪問(wèn)權(quán)限mode&~掩碼如,002表示屏蔽W假設(shè):mode=(111)2掩碼:010則訪問(wèn)權(quán)限:111^101 101 RWX53有名管道讀寫(xiě)規(guī)則從FIFO中讀取數(shù)據(jù)如果有進(jìn)程寫(xiě)打開(kāi)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,以提醒以后再試。阻塞原因當(dāng)前FIFO內(nèi)有數(shù)據(jù),但有其他進(jìn)程在讀數(shù)據(jù)該FIFO當(dāng)前FIFO內(nèi)沒(méi)有數(shù)據(jù)沒(méi)有進(jìn)程寫(xiě)打開(kāi)54有名管道讀寫(xiě)規(guī)則向FIFO中寫(xiě)入數(shù)據(jù)當(dāng)要寫(xiě)入的數(shù)據(jù)的數(shù)據(jù)量不大于PIPE_BUF時(shí),Linux將保證寫(xiě)入的原子性。如果此時(shí)管道空閑緩沖區(qū)不足以容納要寫(xiě)入的字節(jié)數(shù),則進(jìn)入睡眠,直到空閑緩沖區(qū)緩沖區(qū)足以寫(xiě)入時(shí),才開(kāi)始寫(xiě)操作當(dāng)寫(xiě)入的數(shù)據(jù)量大于PIPE_BUF時(shí),Linux將不再保證原子性。FIFO緩沖區(qū)一有空閑區(qū)域,寫(xiě)進(jìn)程試圖寫(xiě)入數(shù)據(jù),寫(xiě)操作在寫(xiě)完所有請(qǐng)求寫(xiě)的數(shù)據(jù)后返回/usr/include/linux/limits.h中(RedHAT)# define
PIPE_BUF
409655范例**#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<fcntl.h>intmain(){ charbuffer[80]; intfd; unlink(“myfifo”);/*FIFO文件必須是不存在*/ if((mkfifo("myfifo",0666)<0)&&(errno!=EEXIST))//讀寫(xiě)權(quán)限
printf("cannotcreatefifoserver\n"); if(fork()>0){ chars[]="hello!\n"; fd=open("myfifo",O_WRONLY); write(fd,s,sizeof(s)); close(fd); } else{ fd=open("myfifo",O_RDONLY); read(fd,buffer,80); printf("%s",buffer); close(fd); } exit(0);}//fifo——execl應(yīng)用56//fiforead.c**#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>intmain(){ charbuffer[80]; intfd; fd=open("myfifo",O_RDONLY); read(fd,buffer,80); printf("%s\n",buffer); close(fd); exit(0);}57//fifowrite.c**#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>intmain(){ charbuffer[80]; intfd; chars[]="hello!\n"; fd=open("myfifo",O_WRONLY); write(fd,s,sizeof(s)); close(fd); exit(0);}58//利用execl函數(shù)調(diào)用有名管道讀寫(xiě)程序***#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<fcntl.h>intmain(){ unlink("myfifo"); if((mkfifo("myfifo",0666)<0)&&(errno!=EEXIST))//讀寫(xiě)權(quán)限
printf("cannotcreatefifoserver\n"); printf("errono:%d\n",errno"); } if(fork()==0) if(execl("fifowrite",NULL)<0) perror("Erronexecl"); if(fork()==0) if(execl("fiforead",NULL)<0) perror("Erronexecl"); exit(0); return(0);}597.2.3命名管道例7.7***:設(shè)計(jì)兩個(gè)程序,要求用命名管道FIFO,實(shí)現(xiàn)簡(jiǎn)單的聊天功能。60#include<stdio.h>#include<fcntl.h>#include<string.h>#include<stdlib.h>#include<sys/select.h>#include<sys/types.h>#include<sys/stat.h>#include<errno.h>intmain(){ inti,rfd,wfd,len=0,fd_in; charstr[32]; intflag,stdinflag; fd_setwrite_fd,read_fd; structtimevalnet_timer; umask(0111); if(mkfifo(“/home/2009/yjfifo1“,0666)<0) /*mkfifo函數(shù)創(chuàng)建命名管道*/ perror("mkfifo"); if(mkfifo("/home/2009/yjfifo2",0666)<0) /*mkfifo函數(shù)創(chuàng)建命名管道*/ perror("mkfifo"); rfd=open("/home/2009/yjfifo1",O_RDONLY); /*以只讀方式打開(kāi)管道文件*/ wfd=open("/home/2009/yjfifo2",O_WRONLY); /*以寫(xiě)方式打開(kāi)管道文件*/ if(rfd<=0||wfd<=0) return0; printf("ThisisLiSi!\n"); FD_ZERO(&read_fd); /*清除一個(gè)文件描述符集*/
實(shí)例***61while(1) {
FD_SET(rfd,&read_fd);/*將文件描述符rfd加入文件描述符集read_fd*/ FD_SET(fileno(stdin),&read_fd); net_timer.tv_sec=5; net_timer.tv_usec=0; memset(str,0,sizeof(str));/*memset函數(shù)初始化清空*/ if(i=select(rfd+1,&read_fd,NULL,NULL,&net_timer)<=0) continue; if( FD_ISSET(rfd,&read_fd)) { read(rfd,str,sizeof(str));/*讀取管道,將管道內(nèi)容存入str變量*/ printf("\n"); printf("ZhangSan:%s\n",str); /*打印輸出str變量?jī)?nèi)容*/ } if( FD_ISSET(fileno(stdin),&read_fd)) { printf("\n"); fgets(str,sizeof(str),stdin); len=write(wfd,str,strlen(str)); /*寫(xiě)入管道*/ } } close(rfd); close(wfd);}62I/O處理的多工機(jī)制
select()函數(shù)*監(jiān)視多個(gè)文件/設(shè)備等待讀寫(xiě)(阻塞)異常情況I/O(0)輸出設(shè)備輸入設(shè)備文件讀/寫(xiě)輸入設(shè)備輸入設(shè)備輸出設(shè)備輸出設(shè)備63Selec()函數(shù)*#include<sys/select.h>#include<sys/time.h>intselect(intmaxfd,/*指定測(cè)試的描述符最大值*/
fd_set*readfds,/*被監(jiān)視的讀文件描述符集*/ fd_set*writefds,/*被監(jiān)視的寫(xiě)文件描述符集*/ fd_set*exceptfds,/*被監(jiān)視的異常處理文件描述符集*/ conststructtimeval*timeout);/*等待時(shí)間*/
64返回值: 成功:文件描述符狀態(tài)已改變的個(gè)數(shù) 如果為0:timeout(超時(shí)) 失敗:-1,錯(cuò)誤代碼errno功能用來(lái)監(jiān)視多個(gè)文件描述符(filedescrīptor)的狀態(tài)(可讀、可寫(xiě)或異常)變化的。程序會(huì)停在select這里等待,直到被監(jiān)視的文件描述符有某一個(gè)或多個(gè)發(fā)生了狀態(tài)改變。
Selec()函數(shù)*65timeval的結(jié)構(gòu)定義如下:structtimeval{ longtv_sec; //表示幾秒
longtv_usec;//表示幾微妙}timeout取不同的值,該調(diào)用就表現(xiàn)不同的性質(zhì):1.timeout為0,調(diào)用立即返回;2.timeout為NULL,select()調(diào)用就阻塞,直到知道有文件描述符就緒;3.timeout為正整數(shù),就是一般的定時(shí)器。
66文件描述符集的處理(宏)*FD_ZERO(fd_set*fdset):清除文件描述符集fdset中的所有位(既把所有位都設(shè)置為0)FD_SET(intfd,fd_set*fdset):設(shè)置文件描述符集fdset中對(duì)應(yīng)于文件描述符fd的位(設(shè)置為1)FD_CLR(intfd,fd_set*fdset):清除文件描述符集fdset中對(duì)應(yīng)于文件描述符fd的位(設(shè)置為0)
FD_ISSET(intfd,fdset*fdset):檢測(cè)文件描述符集fdset中對(duì)應(yīng)于文件描述符fd的位是否被設(shè)置
Fd_set:一個(gè)位圖類型的數(shù)據(jù)集67文件描述符集描述符集通常用整數(shù)數(shù)組中的位域表示,數(shù)組元素的每一位對(duì)應(yīng)一個(gè)文件描述符。例如,一個(gè)整數(shù)占32位,那么整數(shù)數(shù)組的第一個(gè)元素代表文件描述符0到31,數(shù)組的第二個(gè)元素代表文件描述符32到63,以此類推。68文件描述符集文件描述符在形式上是一個(gè)非負(fù)整數(shù)。實(shí)際上,它是一個(gè)索引值,指向內(nèi)核為每一個(gè)進(jìn)程所維護(hù)的該進(jìn)程打開(kāi)文件的記錄表。當(dāng)程序打開(kāi)一個(gè)現(xiàn)有文件或者創(chuàng)建一個(gè)新文件時(shí),內(nèi)核向進(jìn)程返回一個(gè)文件描述符。在程序設(shè)計(jì)中,一些涉及底層的程序編寫(xiě)往往會(huì)圍繞著文件描述符展開(kāi)。但是文件描述符這一概念往往只適用于UNIX、Linux這樣的操作系統(tǒng)。69文件描述符集#include<sys/select.h>#include<sys/time.h>fd_setreadset;FD_ZERO(&readset);FD_SET(5,&readset);FD_SET(33,&readset);FD_CLR(5,&readset);70范例:檢測(cè)有鍵盤(pán)輸入(標(biāo)準(zhǔn)輸入文件描述符:0)*#include<stdio.h>#include<unistd.h>#include<sys/select.h>#include<sys/time.h>Intmain(){ charbuf[80]; fd_setrdfds; structtimevaltv; intret; while(1){ FD_ZERO(&rdfds); FD_SET(0,&rdfds); tv.tv_sec=1; tv.tv_usec=0; ret=select(1,&rdfds,NULL,NULL,&tv);/*注意最大值還要加1*/ if(ret<0)perror("select"); /*出錯(cuò)*/ if(ret==0)printf("timeout\n"); /*在設(shè)定的時(shí)間tv內(nèi),用戶沒(méi)有按鍵盤(pán)*/ else{ /*用戶有按鍵盤(pán),要讀取用戶的輸入*/ scanf("%s",buf); printf("%s\n",buf); } } return(0);}71課堂練習(xí)***試編寫(xiě)?yīng)毩⒌?個(gè)程序,要求分別完成如下功能:第一個(gè)程序每隔一秒產(chǎn)生1~100之間的隨機(jī)數(shù)(可用sleep函數(shù));將數(shù)據(jù)寫(xiě)入有名管道;第二個(gè)程序從有名管道讀取數(shù)據(jù),并顯示;采用select函數(shù)限定阻塞等待時(shí)間為2秒。第三個(gè)程序創(chuàng)建有名管道;分別創(chuàng)建兩個(gè)子進(jìn)程,并分別調(diào)用execl函數(shù)執(zhí)行程序1和程序2;接收CTL_C信號(hào)后向前兩個(gè)進(jìn)程發(fā)送結(jié)束信號(hào);等待2個(gè)子進(jìn)程結(jié)束后退出。7.3消息隊(duì)列消息隊(duì)列,就是一個(gè)消息的鏈表,是一系列保存在內(nèi)核中的消息的列表。用戶進(jìn)程可以向消息隊(duì)列尾部添加消息,也可以從消息隊(duì)列讀取消息,與管道通信非常相似。消息~是大小有限的數(shù)據(jù)塊(LINUX)(msg.h)每個(gè)消息的最大字節(jié)數(shù)MSGMAX:8192*消息隊(duì)列的最大長(zhǎng)度MSGMNB:16384消息隊(duì)列的優(yōu)勢(shì):對(duì)每個(gè)消息指定特定消息類型,接收的時(shí)候不需要按隊(duì)列次序,而是可以根據(jù)自定義條件接收特定類型的消息??梢园严⒖醋饕粋€(gè)記錄,具有特定的格式以及特定的優(yōu)先級(jí)。7273消息隊(duì)列操作*與FIFO類似,但不需要open/close操作創(chuàng)建消息隊(duì)列標(biāo)識(shí)符(queueID)。ftok()創(chuàng)建一個(gè)IPC函數(shù)所需的關(guān)鍵字key(某一資源識(shí)別代號(hào)).Msgget()~創(chuàng)建一個(gè)新隊(duì)列或打開(kāi)一個(gè)存在的隊(duì)列;Sgsnd()~向隊(duì)列末端添加一條新消息;Msgrcv()~從隊(duì)列中讀取消息,讀取消息是不一定遵循先進(jìn)先出的,也可以按消息的類型字段取消息.Msgctl()~消息隊(duì)列控制(刪除)
74消息隊(duì)列相關(guān)函數(shù)ftok函數(shù)#include<sys/types.h>#include<sys/ipc.h>Key_tftok(char*pathname,charproj)Pathname~必須是一個(gè)存在的可訪問(wèn)的路徑或文件;Proj(子序號(hào))~不得為0。功能:根據(jù)pathname和proj來(lái)創(chuàng)建一個(gè)systemVIPC函數(shù)所需的關(guān)鍵字key(代表某一資源的識(shí)別代號(hào)).75例*:#include<sys/types.h>#include<sys/ipc.h>key_tmykey;mykey=ftok(“/home/usr1/SHMkey”,1);或mykey=ftok(“.”,’a’);//與當(dāng)前路徑結(jié)合產(chǎn)生key76創(chuàng)建/打開(kāi)消息隊(duì)列*
:
#include<sys/types.h>#include<sys/ipc.h>#include<sys/msg.h>intmsgget(key_tkey,intmsgflg)
功能:創(chuàng)建一個(gè)新隊(duì)列或打開(kāi)一個(gè)存在的隊(duì)列.返回值:成功則返回消息隊(duì)列ID,出錯(cuò)則返回-1.參數(shù):key:消息隊(duì)列的key值.Msgflg標(biāo)志位~消息隊(duì)列的訪問(wèn)權(quán)限IPC_CREAT~生成新的消息隊(duì)列IPC_PRIVATE~僅為當(dāng)前進(jìn)程所訪問(wèn)77消息隊(duì)列創(chuàng)建APIintopen_queue(key_tkeyval){ int qid; if((qid=msgget(keyval,IPC_CREAT|0660))==-1) { return(-1); } return(qid);}78向隊(duì)列添加一條消息*intmsgsnd(intmsqid,structmsgbuf*msgp,intmsgsz,intmsgflg);
功能:向消息隊(duì)列發(fā)送一個(gè)消息.參數(shù):Msgid~消息隊(duì)列IDMsgp~指向即將發(fā)送的消息(存儲(chǔ)在的msgbuf結(jié)構(gòu)中),Msgze~消息的大小。Msgflg~用來(lái)控制消息隊(duì)列滿載時(shí),若設(shè)置了IPC_NOWAIT,則在消息隊(duì)列沒(méi)有足夠空間時(shí)立即返回,否則等待直到滿足條件。79structmsgbuf{ longmtype;/*typeofmessage*/ charmtext[];/*messagetext*/
…
…};80添加消息隊(duì)列APIintsend_message(intqid,structmsgbuf*qbuf){ int result,length; length=sizeof(structmsgbuf)-sizeof(long); if((result=msgsnd(qid,qbuf,length,0))==-1) return(-1); return(result);}81從消息隊(duì)列中讀取一個(gè)消息*intmsgrcv(intmsqid,structmsgbuf*msgp,intmsgsz,longmsgtyp,intmsgflg);
功能:從msgid代表的消息隊(duì)列中讀取一個(gè)消息,并把消息存儲(chǔ)在msgp指向的msgbuf結(jié)構(gòu)中。返回:成功~返回實(shí)際讀到的信息數(shù)據(jù)長(zhǎng)度。 失敗~返回-1主要參數(shù)Msqid~消息隊(duì)列描述字;Msgsz~指定msgbuf的長(zhǎng)度(即消息內(nèi)容的長(zhǎng)度)82從消息隊(duì)列中讀取一個(gè)消息Msgtyp~請(qǐng)求讀取的消息類型;Msgtyp=0~接收第一個(gè)到來(lái)的消息;Msgtyp〉0~接收第一個(gè)到來(lái)的與此類型相同的消息;Msgtyp<0~接收第一個(gè)到來(lái)的等于或小于此類型絕對(duì)值的消息;Msgflg~消息標(biāo)志。可以為以下幾個(gè)常值的或:IPC_NOWAIT~如果沒(méi)有滿足條件的消息,調(diào)用立即返回;IPC_EXCEPT~與msgtyp>0配合使用,返回隊(duì)列中第一個(gè)類型不為msgtyp的消息;IPC_NOERROR~如果隊(duì)列中滿足條件的消息內(nèi)容大于所請(qǐng)求的msgsz字節(jié),則把該消息截?cái)?,截?cái)嗖糠謱G失。Msgflg=0時(shí),msgsnd()及msgrcv()在隊(duì)列呈滿或呈空的情形時(shí),采取阻塞等待的處理模式83從消息隊(duì)列中讀取一個(gè)消息APIintread_message(intqid,longtype,structmymsgbuf*qbuf){intresult,length;length=sizeof(structmymsgbuf)-sizeof(long);if((result=msgrcv(qid,qbuf,length,type,0))==-1) return(-1);return(result);}84消息隊(duì)列控制msgctl()*intmsgctl(intmsqid,intcmd,structmsqid_ds*buf);
調(diào)用返回:成功返回0,否則返回-1。cmd操作,共有三種cmd操作IPC_STAT、IPC_SET、IPC_RMID。IPC_STAT:該命令用來(lái)獲取消息隊(duì)列信息,返回的信息存貯在buf指向的msqid結(jié)構(gòu)中;IPC_SET:該命令用來(lái)設(shè)置消息隊(duì)列的屬性,要設(shè)置的屬性存儲(chǔ)在buf指向的msqid結(jié)構(gòu)中;可設(shè)置屬性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同時(shí),也影響msg_ctime成員。IPC_RMID:刪除msqid標(biāo)識(shí)的消息隊(duì)列;
85范例:刪除消息隊(duì)列*msgctl(mqid,IPC_RMID,NULL);867.3消息隊(duì)列例7.8**:設(shè)計(jì)一個(gè)程序,要求創(chuàng)建消息隊(duì)列,輸入的文字添加到消息隊(duì)列后,讀取隊(duì)列中的消息輸出。源程序代碼:8788由此例可知,進(jìn)程間通過(guò)消息隊(duì)列通信,主要是創(chuàng)建或打開(kāi)消息隊(duì)列、添加消息、讀取消息和控制消息隊(duì)列這四種操作。89#include<sys/ipc.h>#include<sys/msg.h>#include<sys/stat.h>#include<sys/types.h>#include<stdio.h>#include<fcntl.h>#include<signal.h>#include<stdlib.h>#include<string.h>#definePROJID0xFF#defineLUCY1#definePETER2intmqid;voidterminate_handler(intsigno){ msgctl(mqid,IPC_RMID,NULL); exit(0);}實(shí)例**
90intmain(){ charfilenm[]="msg"; key_tmqkey; structmsgbuf{ longmtype; /*messagetype,mustbe>0*/ charmtext[256];/*messagedata*/ }msg; intret; mqkey=ftok(filenm,PROJID); if(mqkey==-1){ perror("ftokerror:"); exit(-1); } mqid=msgget(mqkey,IPC_CREAT|0666); if(mqid==-1){ perror("msggeterror:"); exit(-1); } signal(SIGINT,terminate_handler); signal(SIGTERM,terminate_handler); while(1){ printf("Lucy:"); fgets(msg.mtext,256,stdin); if(strncmp("quit",msg.mtext,4)==0){ msgctl(mqid,IPC_RMID,NULL); exit(0); } msg.mtext[strlen(msg.mtext)-1]='\0'; msg.mtype=LUCY; msgsnd(mqid,&msg,strlen(msg.mtext)+1,0); msgrcv(mqid,&msg,256,0,0); printf("Peter:%s\n",msg.mtext); }}91課堂練習(xí)仿照例7-7,采用消息隊(duì)列操作編寫(xiě)簡(jiǎn)易聊天程序。作業(yè)FIFO和消息隊(duì)列機(jī)制的對(duì)比分析7.4共享內(nèi)存93Linux中進(jìn)程間通信進(jìn)程1進(jìn)程2管道pipesignal消息隊(duì)列共享內(nèi)存共享內(nèi)存Mmap建立共享內(nèi)存映射Munmap建立共享內(nèi)存映射文件操作內(nèi)存操作Memcpystrcpy文件內(nèi)存95一、系統(tǒng)V共享內(nèi)存概述共享內(nèi)存*特定的內(nèi)存中一段存儲(chǔ)區(qū)多個(gè)進(jìn)程共享此存儲(chǔ)區(qū)特點(diǎn)*最快的IPC方式信息量大數(shù)據(jù)可維持共享內(nèi)存原理示意圖96≈≈二、共享內(nèi)存操作步驟*≈≈創(chuàng)建共享內(nèi)存或打開(kāi)映射共享內(nèi)存讀/寫(xiě)操作共享內(nèi)存解除共享內(nèi)存映射控制共享內(nèi)存(刪除)97≈≈二、共享內(nèi)存操作步驟*≈≈創(chuàng)建共享內(nèi)存或打開(kāi)(已有的shm)映射共享內(nèi)存讀/寫(xiě)操作共享內(nèi)存解除共享內(nèi)存映射控制共享內(nèi)存(刪除)98三、共享內(nèi)存API*創(chuàng)建共享內(nèi)存~shmget()用來(lái)獲得共享內(nèi)存區(qū)域的ID,如果不存在指定的共享區(qū)域就創(chuàng)建相應(yīng)的區(qū)域。映射共享內(nèi)存~shmat()當(dāng)前進(jìn)程與共享內(nèi)存區(qū)連接。撤銷共享內(nèi)存~shmdt()解除當(dāng)前進(jìn)程與共享內(nèi)存區(qū)的映射??刂乒蚕韮?nèi)存~shmctl()實(shí)現(xiàn)對(duì)共享內(nèi)存區(qū)域的控制操作(刪除)。99三、共享內(nèi)存API(1)—?jiǎng)?chuàng)建* #include<sys/ipc.h>#include<sys/shm.h>intshmget(key_tkey,size_tsize,intshmflg)參數(shù):名字(key):ftok()或整形數(shù)大小(size):字節(jié)為單位訪問(wèn)方式(shmflg):讀、寫(xiě),etc.訪問(wèn)權(quán)限:所有者、同組用戶、其他用戶(UGO)如,0644(同組和其他用戶只讀)可與IPC_CREAT進(jìn)行邏輯或,表示創(chuàng)建新的共享內(nèi)存或讀取已有的共享內(nèi)存IPC_CREATE:表明要?jiǎng)?chuàng)建新的共享內(nèi)存空間。IPC_EXCL:只有在共享內(nèi)存不存在的時(shí)候,新的共享內(nèi)存才建立,否則就產(chǎn)生錯(cuò)誤。IPC_EXEL標(biāo)志本身并沒(méi)有太大的意義,但是和IPC_CREAT標(biāo)志一起使用可以用來(lái)保證所得的對(duì)象是新建的,而不是打開(kāi)已有的對(duì)象。返回:標(biāo)識(shí)(ID)
100intshmget(key_tkey,size_tsize,intshmflg)成功返回共享內(nèi)存的標(biāo)識(shí)符;不成功返回-1,errno儲(chǔ)存錯(cuò)誤原因。EINVAL
參數(shù)size小于SHMMIN或大于SHMMAX。EEXIST
預(yù)建立key所致的共享內(nèi)存,但已經(jīng)存在。EIDRM
參數(shù)key所致的共享內(nèi)存已經(jīng)刪除。ENOSPC
超過(guò)了系統(tǒng)允許建立的共享內(nèi)存的最大值 (SHMALL)。ENOENT
參數(shù)key所指的共享內(nèi)存不存在,參數(shù)shmflg 也未設(shè)IPC_CREAT位。EACCES
沒(méi)有權(quán)限。ENOMEM
核心內(nèi)存不足。
注:perror(“操作”)的執(zhí)行后將以errno(錯(cuò)誤代碼)的值來(lái)決定輸出的字符串。101創(chuàng)建共享內(nèi)存*示例#include<sys/ipc.h>#include<sys/shm.h>….int shmid,shmSize=1024;key_tshmKey;shmKey=ftok(“.”,’a’);shmId=shmget(shmKey,shmSize,IPC_CREAT|0666)102三、共享內(nèi)存API(2)—映射*#include<sys/types.h>#include<sys/shm.h>void*shmat(intshmid,constvoid*shmaddr,intshmflg);功能:將當(dāng)前進(jìn)程與共享內(nèi)存連接,即獲取共享內(nèi)存首地址。參數(shù):
shmid:shnget的返回值
shmaddr:當(dāng)前進(jìn)程的地址空間的具體位置。
設(shè)為NULL指針~將由系統(tǒng)指定
shmflg:訪問(wèn)方式。
0~可讀寫(xiě);
SHM_RDONLY~只讀(即使已設(shè)置了寫(xiě)的權(quán)限)103三、共享內(nèi)存API(2)—映射*shmat()函數(shù)返回值成功~返回共享內(nèi)存的首地址失敗~返回-1(錯(cuò)誤原因存于errno中);錯(cuò)誤代碼:EACCES:對(duì)于所請(qǐng)求的連上類型,進(jìn)程沒(méi)有足夠的權(quán)限,并且不具有CAP_IPC_OWNER權(quán)能EINVAL:參數(shù)無(wú)效
ENOMEM:內(nèi)存不足,無(wú)法分配描述詞或頁(yè)表104共享內(nèi)存API(2)—映射*示例char*shmAddr;shmId=shmget(shmKey,shmSize,IPC_CREAT|0666)shmAddr=(char*)shmat(shmId,NULL,0)105共享內(nèi)存API(3)—解除*intshmdt(char*shmaddr);功能:解除進(jìn)程對(duì)共享內(nèi)存區(qū)域的連接。 *進(jìn)程結(jié)束時(shí),脫離共享內(nèi)存。Shmaddr~由smat()返回的共享內(nèi)存地址。返回值0~成功,-1~失?。ㄥe(cuò)誤原因存于errno中)106共享內(nèi)存API(4)—?jiǎng)h除*intshmctl(intshmqid,intcmd,structshmid_ds*buf);返回值:0成功,-1錯(cuò)誤CmdIPC_RMID~刪除共享內(nèi)存IPC_STAT~把共享內(nèi)存的shmid_ds結(jié)構(gòu)復(fù)制到buf107structshmid_ds{structipc_permshm_perm;/*操作權(quán)限*/intshm_segsz;/*段的大小(以字節(jié)為單位)*/time_tshm_atime;/*最后一個(gè)進(jìn)程連接到該段的時(shí)間*/time_tshm_dtime;/*最后一個(gè)進(jìn)程脫離該段的時(shí)間*/time_tshm_ctime;/*最后一次修改這個(gè)結(jié)構(gòu)的時(shí)間*/unsignedshortshm_cpid;/*創(chuàng)建該段進(jìn)程的pid*/unsignedshortshm_lpid;/*在該段上操作的最后一個(gè)進(jìn)程的pid*/shortshm_nattch;/*當(dāng)前連接到該段的進(jìn)程的個(gè)數(shù)*/ unsignedshortshm_npages;/*段的大小(以頁(yè)為單位)*/unsignedlong*shm_pages;/*指向frames->SHMMAX的指針數(shù)組*/structvm_area_struct*attaches;/*對(duì)共享段的描述*/};structipc_perm{
__kernel_key_t
key;
__kernel_uid_t
uid;
__kernel_gid_t
gid;
__kernel_uid_t
cuid;
__kernel_gid_t
cgid;
__kernel_mode_tmode;
unsignedshort
seq;
};108char*initShrMem(intshmKey,intshmSize){char*shmAddr; /*創(chuàng)建共享內(nèi)存*/if((shmId=shmget(shmKey,shmSize,IPC_CREAT|0666))==-1) return-1;/*共享內(nèi)存與目前進(jìn)程的連接*/if((int)(shmAddr=(char*)shmat(shmId,0,0))==-1){/*共享內(nèi)存的釋放*/shmctl(shmId,IPC_RMID,NULL);shmId=0;return-1;}/*共享內(nèi)存的初始化*/memset(shmAddr,'\0',shmSize);return(shmAddr);}共享內(nèi)存初始化范例***109intexitShrMem(char*shmAddr){/*使共享內(nèi)存脫離進(jìn)程*/if(shmdt(shmAddr)==-1){ perror("detacherror"); return-1;}/*共享內(nèi)存釋放*/if(shmctl(shmId,IPC_RMID,NULL)==-1){ perror("detacherror"); return-1;}return1;}共享內(nèi)存撤銷范例***110共享內(nèi)存的讀寫(xiě)***#include<string.h>(1)voidmemcpy(void*dest,//目的地址
constvoid*src,//源地址
siz_tn)//拷貝的字節(jié)數(shù)(2)voidstrcpy(void*dest,//目的地址
constvoid*src,//源地址
siz_tn)//拷貝的字節(jié)數(shù)≈≈111共享內(nèi)存操作引例***
創(chuàng)建共享內(nèi)存創(chuàng)建子進(jìn)程子進(jìn)程連接共享內(nèi)存寫(xiě)共享內(nèi)存脫離共享內(nèi)存父進(jìn)程讀共享內(nèi)存連接共享內(nèi)存讀共享內(nèi)存狀態(tài)信息讀共享內(nèi)存數(shù)據(jù)脫離共享內(nèi)存刪除讀共享內(nèi)存112//shm0.c共享內(nèi)存操作引例***
#include<string.h>#include<sys/ipc.h>#include<sys/shm.h>#include<sys/types.h>#defineKEY1234#defineSIZE1024intmain(){ intshmid,pid; char*shmaddr; structshmid_dsbuf;
shmid=shmget(KEY,SIZE,IPC_CREAT|0666); if((pid=fork())==0){ printf("Myparent'pid=%d\n",getppid());
shmaddr=(char*)shmat(shmid,NULL,0); strncpy(shmaddr,"Hi!Iamchildprocess!\n“); shmdt(shmaddr); return1; }113else{ printf("childpid=%d\n",pid); sleep(1);
shmctl(shmid,IPC_STAT,&buf);
/*段的大小(以字節(jié)為單位)*/ printf("shm_segsz=%d\n",buf.shm_segsz);
/*創(chuàng)建該段進(jìn)程的pid*/ printf("shm_cpid=%d\n",buf.shm_cpid); /*在該段上操作的最后一個(gè)進(jìn)程的pid*/ printf("shm_lpid=%d\n",buf.shm_lpid);
shmaddr=(char*)shmat(shmid,NULL,0); /*讀取共享內(nèi)存*/ printf("%s",shmaddr); shmdt(shmaddr); shmctl(shmid,IPC_RMID,NULL); }}114共享內(nèi)存實(shí)例**分別編寫(xiě)兩個(gè)程序,完成共享內(nèi)存的讀與寫(xiě)操作。要求: 待寫(xiě)入的數(shù)據(jù)為隨機(jī)浮點(diǎn)數(shù); 每隔一秒采集一次不同通道(共8個(gè)),并寫(xiě)入共享內(nèi)存;
循環(huán)寫(xiě)入無(wú)限次;
ctl_c退出程序。
通道選擇開(kāi)關(guān)1N0IN1IN2IN3IN4IN5IN6IN7ABC收發(fā)進(jìn)程1115共享內(nèi)存實(shí)例**數(shù)據(jù)結(jié)構(gòu)定義typedefstruct{ intch; /*通道號(hào)*/ doublepower;/*被測(cè)數(shù)據(jù)*/}data;116//shm_com.h**/*Acommonheaderfiletodescribethesharedmemorywewishtopassabout.*/#include<unistd.h>#include<string.h>#include<stdlib.h>#include<sys/ipc.h>#include<sys/shm.h>#include<signal.h>#include<sys/types.h>#define NUMBER8typedefstruct{ intch; doublepower;}data;117//shm1.c**#include"shm_com.h"intexitSig=0;voidexitProc(intn){ printf("Ctrl_C\n"); exitSig=1; raise(SIGHUP);}intmain(){ intshm_id,i; key_tkey;
data*p_map,*pshmwr,wdata;
(void)signal(SIGINT,exitProc); key=ftok(".",'a'); if(key==-1) perror("ftokerror");
shm_id=shmget(key,sizeof(data)*NUMBER,IPC_CREAT|0666); if(shm_id==-1){ perror("shmgeterror"); return; }118
p_map=(data*)shmat(shm_id,NULL,0); if(p_map==(data*)-1){ perror("shmaterror"); return; } while(!exitSig) { pshmwr=p_map; for(i=0;i<NUMBER;i++) { wdata.ch=i; wdata.power=drand48()*10.0;/*隨機(jī)浮點(diǎn)數(shù)*/
memcpy(pshmwr,&wdata,sizeof(data)); printf("ch=%dpower=%f\n",pshmwr->ch,pshmwr->power); pshmwr++; sleep(1); } } if(shmdt(p_map)==-1) perror("detacherror");}119//shm2.c**#include"shm_com.h"intexitSig=0;voidexitProc(intn){ printf("Ctrl_C\n"); exitSig=1; raise(SIGHUP);}intmain(){ intshm_id,i; key_tkey; data*p_map,*pshmrd,rdata;
(void)signal(SIGINT,exitProc); key=ftok(".",'a'); if(key==-1) perror("ftokerror");
shm_id=shmget(key,sizeof(data)*NUMBER,IPC_CREAT|0666); if(shm_id==-1){ perror("shmgeterror"); return; }120
p_map=(data*)shmat(shm_id,NULL,0); if(p_map==(data*)-1){ perror("shmaterror"); return; } while(!exitSig){ pshmrd=p_map; for(i=0;i<NUMBER;i++) {
memcpy(&rdata,pshmrd,sizeof(data));
printf("ch=%dpower=%f\n",rdata.ch,rdata.power); pshmrd++; sleep(1); } }
if(shmdt(p_map)==-1)
perror("detacherror"); if(shmctl(shm_id,IPC_RMID,NULL)==-1)
perror("shmctlerror");}121課外補(bǔ)充(1)信號(hào)量**在多用戶、多任務(wù)系統(tǒng)中,對(duì)某一資源排他操作信號(hào)量提供對(duì)進(jìn)程間共享資源訪問(wèn)控制機(jī)制,相當(dāng)于內(nèi)存中的標(biāo)志。進(jìn)程可以根據(jù)它判定是否能夠訪問(wèn)某些共享資源,同時(shí),進(jìn)程也可以修改該標(biāo)志。除了用于訪問(wèn)控制外,還可用于進(jìn)程同步。共享資源(M/IO)122信號(hào)量**信號(hào)量對(duì)臨界段操作,需要確保只有一個(gè)進(jìn)程獨(dú)占P(sv)操作若sv>0則sv-1,若sv=0則讓進(jìn)程暫停,等待對(duì)共享資源的操作V(sv)操作如果有等待對(duì)共享資源的操作的進(jìn)程,即等待Sv>0,則該進(jìn)程繼續(xù)執(zhí)行。如果沒(méi)有等待進(jìn)程,則sv+1臨界有效(空閑)時(shí),sv=true(>0),執(zhí)行P(sv)操作,使得sv變?yōu)閒alse,臨界忙臨界無(wú)效(忙)時(shí),V(sv),sv=true123信號(hào)量API
**信號(hào)量操作UNIX采用信號(hào)量數(shù)組打開(kāi)或創(chuàng)建信號(hào)量semget()
信號(hào)量值操作semop()獲得或設(shè)置信號(hào)量屬性semctl()
124信號(hào)量的創(chuàng)建*#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>Intsemget(Key_tkey,intnum_sems,intsem_flags)功能:創(chuàng)建一個(gè)新的信號(hào)量,或者獲取一個(gè)已存在的信號(hào)量ID。類似于文件打開(kāi)操作,返回類似于文件描述符的值,信號(hào)量描述符。返回值: 成功~非零值(>0),失敗~-1參數(shù)說(shuō)明:key~標(biāo)識(shí)信號(hào)量資源。與文件名類似。用于不同的進(jìn)程間使用同一個(gè)信號(hào)量的Key;Num_sems:信號(hào)量個(gè)數(shù)。對(duì)于一個(gè)資源,常定義為1;Sem_flags:信號(hào)量訪問(wèn)權(quán)限,如,IPC_CREAT|0666125范例:信號(hào)量**intopenSemId(key_tkey){intsemid; semid=semget(key,1,IPC_CREAT|0666);if(semid==-1){ perror("semget");return-1;}returnsemid;}126*信號(hào)量控制int
semctl(int
semid,int
semnum,int
cmd,union
semun
arg);功能:對(duì)信號(hào)量進(jìn)行一系列的控制。Semid~要操作的信號(hào)描述符Semnum~信號(hào)的個(gè)數(shù)(0:代表1個(gè)信號(hào)量)信號(hào)量是數(shù)組。Cmd~操作的命令.經(jīng)常用的兩個(gè)值是:SETVAL(設(shè)置信號(hào)量的初值)IPC_RMID(刪除信號(hào)量).arg是一個(gè)給cmd的參數(shù).unionsemun{ intval; structsemid_ds*buf; unsignedshort*arry;}127范例:信號(hào)量初始化**intsetSemvalue(intsemid){ unionsemunsemUnion; semUnion.val=1; if(semctl(semid,0,SETVAL,semUnion)==-1)return-1; return1;}128范例:信號(hào)量操作—?jiǎng)h除操作**intdelSemaphore(intsemid){ if(semctl(semid,0,IPC_RMID)==-1){ perror("semctlIPC_RMID"); return-1; } return1;}129信號(hào)量操作(P、V)intsemop(intsemid,structsembuf*semops,unsignednsops);功能: 改變信號(hào)量值。參數(shù):semid~semget()的返回值,信號(hào)量的描述符;Sops~指向一個(gè)結(jié)構(gòu)體數(shù)組的指針; structsembuf{ shortsem_num; //=0(代表第一個(gè)信號(hào)量) shortsem_op; //(-1,1)p,v shortsem_flg; //SEM_UNDO }nsops~sops結(jié)構(gòu)體數(shù)組的個(gè)數(shù),一般設(shè)為1。
130*structsembuf{ shortsem_num;//=0(代表第一個(gè)信號(hào)量) shortsem_op; //(-1,1)p,v shortsem_flg; //SEM_UNDO }Sem_num:欲處理的信號(hào)編號(hào),0代表第一個(gè)信號(hào)量sem_op:-1:對(duì)資源加鎖(P操作)+1:對(duì)資源解鎖(V操作)sem_flg=SEM_UNDO表示進(jìn)程沒(méi)有釋放信號(hào)量而終止的時(shí)候,系統(tǒng)自動(dòng)釋放該進(jìn)程所使用的信號(hào)量。131范例:信號(hào)量操作—P操作**intlockShrMem(intsemId){structsembufsops;sops.sem_num=0;sops.s
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 樂(lè)高教育培訓(xùn)機(jī)構(gòu)合同范本
- 務(wù)工就業(yè)合同范本
- 體育公司合同范本
- 房屋中介購(gòu)新房合同范本
- 制砂機(jī)采購(gòu)合同范本
- 建筑材料采購(gòu)合同范本
- 《國(guó)家計(jì)算機(jī)二級(jí)c語(yǔ)言歷年真題及答案》
- 工程材料欠款合同范本
- 膀胱癌最好的治療方案
- 02S515排水檢查井圖集
- 走進(jìn)魚(yú)類世界智慧樹(shù)知到答案2024年中國(guó)海洋大學(xué)
- 代賣商品合同協(xié)議書(shū)
- 十字相乘法解一元二次方程練習(xí)100題及答案
- 中外合作辦學(xué)規(guī)劃方案
- 廠房屋頂光伏分布式發(fā)電項(xiàng)目建議書(shū)
- 2024年人教版初一道德與法治上冊(cè)期中考試卷(附答案)
- 2024年第九屆“鵬程杯”六年級(jí)語(yǔ)文邀請(qǐng)賽試卷(復(fù)賽)
- 國(guó)開(kāi)2024年《建筑結(jié)構(gòu)#》形考作業(yè)1-4答案
- DL-T1475-2015電力安全工器具配置與存放技術(shù)要求
- 漏檢分析改善措施
評(píng)論
0/150
提交評(píng)論