版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第7章進(jìn)程間的通信2本章重點進(jìn)程通信中信號概念及信號處理進(jìn)程間的管道通信編程進(jìn)程間的內(nèi)存共享編程3Linux中進(jìn)程間通信(IPC)概述**管道、FIFO、信號、消息隊列、信號燈、共享內(nèi)存共享內(nèi)存進(jìn)程1進(jìn)程2管道pipesignal消息隊列4Linux中進(jìn)程間通信概述**管道(Pipe)及有名管道(namedpipe)
管道是一種在進(jìn)程之間單向流動數(shù)據(jù)的結(jié)構(gòu)。源進(jìn)程向管道寫數(shù)據(jù),而內(nèi)核會自動將這些數(shù)據(jù)引導(dǎo)向目標(biāo)進(jìn)程。
管道:用于具有親緣關(guān)系的進(jìn)程間的通信有名管道:除具有管道所具有的功能外,還允許無親緣關(guān)系的進(jìn)程間的通信5Linux中進(jìn)程間通信概述**Linux系統(tǒng)信號(signal)
信號主要用于通知進(jìn)程異步事件的發(fā)生。 在Linux中可以識別29種不同的信號,這些信號中的大部分都有了預(yù)先定義好的意義。6Linux中進(jìn)程間通信概述**消息隊列消息隊列是由內(nèi)核創(chuàng)建并維護(hù)的一個數(shù)據(jù)結(jié)構(gòu),它是有標(biāo)識的。任何具有足夠權(quán)限的進(jìn)程都可以向消息隊列中放置一個消息,同樣,任何具有足夠權(quán)限的進(jìn)程都可以從中讀取一個消息。不同的進(jìn)程通過訪問相同的消息隊列便可實現(xiàn)進(jìn)程間通信。7Linux中進(jìn)程間通信概述**共享內(nèi)存共享內(nèi)存區(qū)是這幾種進(jìn)程間通信方式中最快的一種。它的特點除了速度快外,而且可傳遞的信息量大。通過將一段內(nèi)存區(qū)映射到一個進(jìn)程的地址空間來實現(xiàn)。因此,這種進(jìn)程間通信就不再涉及到內(nèi)核(即進(jìn)程不是通過執(zhí)行任何進(jìn)入內(nèi)核的系統(tǒng)調(diào)用來傳遞數(shù)據(jù)的。內(nèi)核必須建立允許各個進(jìn)程共享該內(nèi)存區(qū)的內(nèi)存映射關(guān)系,然后一直管理該內(nèi)存區(qū))。但同時,也要有效地保證它能同步、有序且沒有死鎖。8Linux中進(jìn)程間通信概述**信號量信號量并不是一種IPC機(jī)制,它是用于提供不同進(jìn)程間或一給定進(jìn)程的不同線程間同步的一種手段。97.1.1信號及其使用
信號是在軟件層次上對中斷機(jī)制的一種模擬,是一種異步通信方式。信號可以直接進(jìn)行用戶空間進(jìn)程和內(nèi)核進(jìn)程之間的交互,內(nèi)核進(jìn)程也可以利用它來通知用戶空間進(jìn)程發(fā)生了哪些系統(tǒng)事件。信號主要用于通知進(jìn)程異步事件的發(fā)生。在Linux中可以識別29種不同的信號,這些信號中的大部分都有了預(yù)先定義好的意義。107.1.1信號及其使用信號事件的發(fā)生有兩個來源:硬件來源,如按下了鍵盤Delete鍵或者鼠標(biāo)單擊,通常產(chǎn)生中斷信號(SIGINT)或者其它硬件故障。軟件來源,如使用系統(tǒng)調(diào)用或者是命令發(fā)出信號。最常用發(fā)送信號的系統(tǒng)函數(shù)是kill、raise、alarm、setitimer、sigation和sigqueue函數(shù),軟件來源還包括一些非法運算等操作。117.1.1信號及其使用**一旦有信號產(chǎn)生,用戶進(jìn)程對信號的響應(yīng)有3種方式:執(zhí)行默認(rèn)操作。Linux對每種信號都規(guī)定了默認(rèn)操作。捕捉信號。定義信號處理函數(shù),當(dāng)信號發(fā)生時,執(zhí)行相應(yīng)的處理函數(shù)。忽略信號。不希望接收到的信號對進(jìn)程的執(zhí)行產(chǎn)生影響,而讓進(jìn)程繼續(xù)進(jìn)行時,可以忽略該信號,即不對信號進(jìn)程任何處理。12信號與信號處理**進(jìn)程A信號產(chǎn)生進(jìn)程B信號處理(信號接收)13常見信號的含義及其默認(rèn)操作*14信號處理常用函數(shù)**發(fā)送信號函數(shù)Kill(pid_tpid,sig);給指定的進(jìn)程發(fā)送信號。raise(intsig);給當(dāng)前進(jìn)程發(fā)送信號。Alarm(unsignedintseconds);給當(dāng)前進(jìn)程發(fā)送時鐘報警信號。pause(void);等待信號到來處理信號函數(shù)-信號捕捉Signal(sig,voidsigfunc(int));信號處理15信號處理常見函數(shù)信號發(fā)送函數(shù)(1)***
#include<sys/types.h>
#include<signal.h>
intkill(pid_tpid,intsig);
說明:
kill()可以用來送參數(shù)sig指定的信號給參數(shù)pid指定的進(jìn)程。
參數(shù)pid有幾種情況:
pid>0將信號傳給進(jìn)程識別碼為pid的進(jìn)程。
pid=0將信號傳給和目前進(jìn)程相同進(jìn)程組的所有進(jìn)程
pid=-1將信號廣播傳送給系統(tǒng)內(nèi)所有的進(jìn)程
返回值: 成功:返回0,錯誤:返回-1。
16信號處理常見函數(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信號處理常見
函數(shù)信號發(fā)送函數(shù)(2)***函數(shù)格式
#include<unistd.h>
定義函數(shù)unsignedintalarm(unsignedintseconds);函數(shù)說明
alarm()用來設(shè)置信號SIGALRM在經(jīng)過參數(shù)seconds指定的秒數(shù)后傳送給目前的進(jìn)程。參數(shù) 若seconds=0,則之前設(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信號處理常見函數(shù)信號捕獲函數(shù)(1)***
#include<signal.h>
void(*signal(intsignum,void(*handler)(int)))(int);
voidsignal(int信號名,信號處理函數(shù)名)信號處理函數(shù)void函數(shù)名(int信號名)函數(shù)說明
signal()會依參數(shù)signum指定的信號編號來設(shè)置該信號的處理函數(shù)。當(dāng)指定的信號到達(dá)時就會跳轉(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ù)*/ pause(); if(exitSig) exit(0); }}/*************
SIGALRM信號處理函數(shù)*************/voidoutDate(intn){ system("date&");/*執(zhí)行外部命令 */}/*************
SIGINT信號處理函數(shù)*************/voidexitProc(intn){ printf("Ctrl_C\n"); exitSig=1;}例:信號的捕捉***227.2.1信號操作的相關(guān)函數(shù)***237.2.1信號操作的相關(guān)函數(shù)24信號操作小結(jié)信號信號的發(fā)送信號的捕捉及處理信號的忽略、阻塞25信號操作小結(jié)信號26信號操作小結(jié)信號的發(fā)送Kill(pid_tpid,sig);給指定的進(jìn)程發(fā)送信號。raise(intsig);給當(dāng)前進(jìn)程發(fā)送信號。Alarm(unsignedintseconds);給當(dāng)前進(jìn)程發(fā)送時鐘報警信號。pause(void);等待信號到來27信號操作小結(jié)信號的捕捉及處理Signal(sig,voidsigfunc(int));信號處理28信號的忽略與阻塞信號的忽略Signal()選項:29信號的忽略與阻塞信號的阻塞有時既不希望進(jìn)程在接收到信號時立刻中斷進(jìn)程的執(zhí)行,也不希望此信號完全被忽略掉,而是延遲一段時間再去調(diào)用信號處理函數(shù),這個時候就需要信號阻塞來完成。步驟清空待處理的信號集追加待處理信號到信號集設(shè)置/解除信號掩碼(設(shè)置屏蔽)307.2.1信號操作的相關(guān)函數(shù)§317.2.1信號操作的相關(guān)函數(shù)327.2.1信號操作的相關(guān)函數(shù)33信號操作小結(jié)信號的忽略、阻塞*信號的忽略Signal(sig,voidsigfunc(int));選項(第2個參數(shù))SIG_IGN:忽略指定的信號SIG_DFL:信號處理方式重新設(shè)為內(nèi)核預(yù)設(shè)方式阻塞步驟清空待處理的信號集:sigempty()追加待處理信號到信號集:sigaddset()設(shè)置/解除信號掩碼(設(shè)置屏蔽):sigprocmask()347.2管道**無名管道(PIPE)有名管道(FIFO)進(jìn)程x進(jìn)程y管道pipe357.2管道**在Linux系統(tǒng)中,管道用于兩個進(jìn)程間的通信,這兩個進(jìn)程要有同源性,即它們必須是最終由同一個進(jìn)程所生成的進(jìn)程。管道通信采用的是半雙工方式,即同一時間只允許單方向傳輸數(shù)據(jù)。進(jìn)程x進(jìn)程y管道pipe367.2管道**在Linux中,管道是一種特殊的文件,對一個進(jìn)程來說,管道的寫入和讀取與一個普通文件沒有區(qū)別。管道是Linux支持的最初UnixIPC形式之一,具有以下特點:管道是半雙工的,數(shù)據(jù)只能向一個方向流動;需要雙方通信時,需要建立起兩個管道;只能用于父子進(jìn)程或者兄弟進(jìn)程之間(具有親緣關(guān)系的進(jìn)程);單獨構(gòu)成一種獨立的文件系統(tǒng):管道對于管道兩端的進(jìn)程而言,就是一個文件,但它不是普通的文件,它不屬于某種文件系統(tǒng),而是自立門戶,單獨構(gòu)成一種文件系統(tǒng),并且只存在與內(nèi)存中。37管道***387.2.1無名管道操作無名管道操作時,建立管道用pipe函數(shù)建立管道后Linux系統(tǒng)會同時為該進(jìn)程建立2個文件描述符pipe_fd[0]和pipe_fd[1]。pipe_fd[0]用來從管道讀取數(shù)據(jù)pipe_fd[1]用來把數(shù)據(jù)寫入管道39無名管道操作**40無名管道操作步驟**創(chuàng)建管道創(chuàng)建進(jìn)程讀/寫寫進(jìn)程關(guān)閉管道的讀端讀進(jìn)程關(guān)閉管道的寫端無名管道操作讀管道進(jìn)程的有關(guān)規(guī)則如果進(jìn)程讀一個寫端關(guān)閉的管道read()返回0,表示結(jié)束。如果進(jìn)程讀一個寫端仍打開的空管道該進(jìn)程休眠,直到管道中有新的輸入。如果進(jìn)程試圖從管道中讀多于現(xiàn)有的字節(jié)返回當(dāng)前的所有內(nèi)容,read()返回實際讀取的字節(jié)。寫端讀端fd[0]fd[1]無名管道操作寫管道進(jìn)程的有關(guān)規(guī)則如果進(jìn)程寫一個讀端關(guān)閉的管道寫操作失敗,將一個SIGPIPE信號發(fā)送給寫進(jìn)程。缺省操作為終止進(jìn)程。如果進(jìn)程寫入管道的字節(jié)數(shù)少于管道能保存的數(shù)write()保證是原子操作,即寫進(jìn)程將完成它的系統(tǒng)調(diào)用,不會被另一個進(jìn)程搶占。寫端讀端fd[0]fd[1]43管道的局限性*
管道的主要局限性正體現(xiàn)在它的特點上:只支持單向數(shù)據(jù)流;只能用于具有親緣關(guān)系的進(jìn)程之間;沒有名字;管道的緩沖區(qū)是有限的(管道制存在于內(nèi)存中,在管道創(chuàng)建時,為緩沖區(qū)分配一個頁面大小);管道所傳送的是無格式字節(jié)流,這就要求管道的讀出方和寫入方必須事先約定好數(shù)據(jù)的格式,比如多少字節(jié)算作一個消息(或命令、或記錄)等等;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無名管道操作例7.5***:設(shè)計一個程序,要求創(chuàng)建一個管道,父進(jìn)程往管道中寫入字符串,子進(jìn)程從管道中讀取前輸出字符串。源程序代碼:487.2.1無名管道操作**497.2.3命名管道*若要在兩個不相關(guān)的進(jìn)程之間用管道通信,需要用到命名管道FIFO。命名管道FIFO是通過Linux系統(tǒng)中的文件進(jìn)行通信。命名管道的創(chuàng)建一般用mkfifo函數(shù),創(chuàng)建成功后,就使用open、read、write等函數(shù)傳輸數(shù)據(jù)。有名管道FIFO不同于管道之處在于它提供一個路徑名與之關(guān)聯(lián),以FIFO的文件形式存在于文件系統(tǒng)中。FIFO嚴(yán)格遵循先進(jìn)先出(firstinfirstout),對管道及FIFO的讀總是從開始處返回數(shù)據(jù),對它們的寫則把數(shù)據(jù)添加到末尾。50有名管道的操作步驟**創(chuàng)建(僅創(chuàng)建一次)~mkfifo()打開(以阻塞形式)~open()省略~阻塞O_NONBLOCK~非阻塞讀/寫~read()/write()關(guān)閉~close()517.2.3命名管道**mkfifo函數(shù)說明說明:如果mkfifo的第一個參數(shù)是一個已經(jīng)存在的路徑名時,會返回EEXIST錯誤,所以一般典型的調(diào)用代碼首先會檢查是否返回該錯誤,如果確實返回該錯誤,那么只要調(diào)用打開FIFO的函數(shù)就可以了。一般文件的I/O函數(shù)都可以用于FIFO,如close、read、write等等。52PGO所有者用戶組其他用戶組RWX讀寫執(zhí)行
0000101001101110:無任何權(quán)限2:只寫4:只讀6:可讀可寫7:可讀可寫可執(zhí)行文件權(quán)限說明*文件權(quán)限由3位8進(jìn)制數(shù)表示,分別代表:掩碼:訪問權(quán)限位的屏蔽字與文件訪問權(quán)限mode&~掩碼如,002表示屏蔽W假設(shè):mode=(111)2掩碼:010則訪問權(quán)限:111^101 101 RWX53有名管道讀寫規(guī)則從FIFO中讀取數(shù)據(jù)如果有進(jìn)程寫打開FIFO,且當(dāng)前FIFO內(nèi)沒有數(shù)據(jù)對于設(shè)置了阻塞標(biāo)志的讀操作來說,一直阻塞;對于沒有設(shè)置了阻塞標(biāo)志的讀操作來說,則返回-1,當(dāng)前errno值為EAGAIN,以提醒以后再試。阻塞原因當(dāng)前FIFO內(nèi)有數(shù)據(jù),但有其他進(jìn)程在讀數(shù)據(jù)該FIFO當(dāng)前FIFO內(nèi)沒有數(shù)據(jù)沒有進(jìn)程寫打開54有名管道讀寫規(guī)則向FIFO中寫入數(shù)據(jù)當(dāng)要寫入的數(shù)據(jù)的數(shù)據(jù)量不大于PIPE_BUF時,Linux將保證寫入的原子性。如果此時管道空閑緩沖區(qū)不足以容納要寫入的字節(jié)數(shù),則進(jìn)入睡眠,直到空閑緩沖區(qū)緩沖區(qū)足以寫入時,才開始寫操作當(dāng)寫入的數(shù)據(jù)量大于PIPE_BUF時,Linux將不再保證原子性。FIFO緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程試圖寫入數(shù)據(jù),寫操作在寫完所有請求寫的數(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))//讀寫權(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)用有名管道讀寫程序***#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))//讀寫權(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è)計兩個程序,要求用命名管道FIFO,實現(xià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); /*以只讀方式打開管道文件*/ wfd=open("/home/2009/yjfifo2",O_WRONLY); /*以寫方式打開管道文件*/ if(rfd<=0||wfd<=0) return0; printf("ThisisLiSi!\n"); FD_ZERO(&read_fd); /*清除一個文件描述符集*/
實例***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變量內(nèi)容*/ } if( FD_ISSET(fileno(stdin),&read_fd)) { printf("\n"); fgets(str,sizeof(str),stdin); len=write(wfd,str,strlen(str)); /*寫入管道*/ } } close(rfd); close(wfd);}62I/O處理的多工機(jī)制
select()函數(shù)*監(jiān)視多個文件/設(shè)備等待讀寫(阻塞)異常情況I/O(0)輸出設(shè)備輸入設(shè)備文件讀/寫輸入設(shè)備輸入設(shè)備輸出設(shè)備輸出設(shè)備63Selec()函數(shù)*#include<sys/select.h>#include<sys/time.h>intselect(intmaxfd,/*指定測試的描述符最大值*/
fd_set*readfds,/*被監(jiān)視的讀文件描述符集*/ fd_set*writefds,/*被監(jiān)視的寫文件描述符集*/ fd_set*exceptfds,/*被監(jiān)視的異常處理文件描述符集*/ conststructtimeval*timeout);/*等待時間*/
64返回值: 成功:文件描述符狀態(tài)已改變的個數(shù) 如果為0:timeout(超時) 失?。?1,錯誤代碼errno功能用來監(jiān)視多個文件描述符(filedescrīptor)的狀態(tài)(可讀、可寫或異常)變化的。程序會停在select這里等待,直到被監(jiān)視的文件描述符有某一個或多個發(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ù),就是一般的定時器。
66文件描述符集的處理(宏)*FD_ZERO(fd_set*fdset):清除文件描述符集fdset中的所有位(既把所有位都設(shè)置為0)FD_SET(intfd,fd_set*fdset):設(shè)置文件描述符集fdset中對應(yīng)于文件描述符fd的位(設(shè)置為1)FD_CLR(intfd,fd_set*fdset):清除文件描述符集fdset中對應(yīng)于文件描述符fd的位(設(shè)置為0)
FD_ISSET(intfd,fdset*fdset):檢測文件描述符集fdset中對應(yīng)于文件描述符fd的位是否被設(shè)置
Fd_set:一個位圖類型的數(shù)據(jù)集67文件描述符集描述符集通常用整數(shù)數(shù)組中的位域表示,數(shù)組元素的每一位對應(yīng)一個文件描述符。例如,一個整數(shù)占32位,那么整數(shù)數(shù)組的第一個元素代表文件描述符0到31,數(shù)組的第二個元素代表文件描述符32到63,以此類推。68文件描述符集文件描述符在形式上是一個非負(fù)整數(shù)。實際上,它是一個索引值,指向內(nèi)核為每一個進(jìn)程所維護(hù)的該進(jìn)程打開文件的記錄表。當(dāng)程序打開一個現(xiàn)有文件或者創(chuàng)建一個新文件時,內(nèi)核向進(jìn)程返回一個文件描述符。在程序設(shè)計中,一些涉及底層的程序編寫往往會圍繞著文件描述符展開。但是文件描述符這一概念往往只適用于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范例:檢測有鍵盤輸入(標(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"); /*出錯*/ if(ret==0)printf("timeout\n"); /*在設(shè)定的時間tv內(nèi),用戶沒有按鍵盤*/ else{ /*用戶有按鍵盤,要讀取用戶的輸入*/ scanf("%s",buf); printf("%s\n",buf); } } return(0);}71課堂練習(xí)***試編寫?yīng)毩⒌?個程序,要求分別完成如下功能:第一個程序每隔一秒產(chǎn)生1~100之間的隨機(jī)數(shù)(可用sleep函數(shù));將數(shù)據(jù)寫入有名管道;第二個程序從有名管道讀取數(shù)據(jù),并顯示;采用select函數(shù)限定阻塞等待時間為2秒。第三個程序創(chuàng)建有名管道;分別創(chuàng)建兩個子進(jìn)程,并分別調(diào)用execl函數(shù)執(zhí)行程序1和程序2;接收CTL_C信號后向前兩個進(jìn)程發(fā)送結(jié)束信號;等待2個子進(jìn)程結(jié)束后退出。7.3消息隊列消息隊列,就是一個消息的鏈表,是一系列保存在內(nèi)核中的消息的列表。用戶進(jìn)程可以向消息隊列尾部添加消息,也可以從消息隊列讀取消息,與管道通信非常相似。消息~是大小有限的數(shù)據(jù)塊(LINUX)(msg.h)每個消息的最大字節(jié)數(shù)MSGMAX:8192*消息隊列的最大長度MSGMNB:16384消息隊列的優(yōu)勢:對每個消息指定特定消息類型,接收的時候不需要按隊列次序,而是可以根據(jù)自定義條件接收特定類型的消息??梢园严⒖醋饕粋€記錄,具有特定的格式以及特定的優(yōu)先級。7273消息隊列操作*與FIFO類似,但不需要open/close操作創(chuàng)建消息隊列標(biāo)識符(queueID)。ftok()創(chuàng)建一個IPC函數(shù)所需的關(guān)鍵字key(某一資源識別代號).Msgget()~創(chuàng)建一個新隊列或打開一個存在的隊列;Sgsnd()~向隊列末端添加一條新消息;Msgrcv()~從隊列中讀取消息,讀取消息是不一定遵循先進(jìn)先出的,也可以按消息的類型字段取消息.Msgctl()~消息隊列控制(刪除)
74消息隊列相關(guān)函數(shù)ftok函數(shù)#include<sys/types.h>#include<sys/ipc.h>Key_tftok(char*pathname,charproj)Pathname~必須是一個存在的可訪問的路徑或文件;Proj(子序號)~不得為0。功能:根據(jù)pathname和proj來創(chuàng)建一個systemVIPC函數(shù)所需的關(guān)鍵字key(代表某一資源的識別代號).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)建/打開消息隊列*
:
#include<sys/types.h>#include<sys/ipc.h>#include<sys/msg.h>intmsgget(key_tkey,intmsgflg)
功能:創(chuàng)建一個新隊列或打開一個存在的隊列.返回值:成功則返回消息隊列ID,出錯則返回-1.參數(shù):key:消息隊列的key值.Msgflg標(biāo)志位~消息隊列的訪問權(quán)限IPC_CREAT~生成新的消息隊列IPC_PRIVATE~僅為當(dāng)前進(jìn)程所訪問77消息隊列創(chuàng)建APIintopen_queue(key_tkeyval){ int qid; if((qid=msgget(keyval,IPC_CREAT|0660))==-1) { return(-1); } return(qid);}78向隊列添加一條消息*intmsgsnd(intmsqid,structmsgbuf*msgp,intmsgsz,intmsgflg);
功能:向消息隊列發(fā)送一個消息.參數(shù):Msgid~消息隊列IDMsgp~指向即將發(fā)送的消息(存儲在的msgbuf結(jié)構(gòu)中),Msgze~消息的大小。Msgflg~用來控制消息隊列滿載時,若設(shè)置了IPC_NOWAIT,則在消息隊列沒有足夠空間時立即返回,否則等待直到滿足條件。79structmsgbuf{ longmtype;/*typeofmessage*/ charmtext[];/*messagetext*/
…
…};80添加消息隊列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從消息隊列中讀取一個消息*intmsgrcv(intmsqid,structmsgbuf*msgp,intmsgsz,longmsgtyp,intmsgflg);
功能:從msgid代表的消息隊列中讀取一個消息,并把消息存儲在msgp指向的msgbuf結(jié)構(gòu)中。返回:成功~返回實際讀到的信息數(shù)據(jù)長度。 失敗~返回-1主要參數(shù)Msqid~消息隊列描述字;Msgsz~指定msgbuf的長度(即消息內(nèi)容的長度)82從消息隊列中讀取一個消息Msgtyp~請求讀取的消息類型;Msgtyp=0~接收第一個到來的消息;Msgtyp〉0~接收第一個到來的與此類型相同的消息;Msgtyp<0~接收第一個到來的等于或小于此類型絕對值的消息;Msgflg~消息標(biāo)志??梢詾橐韵聨讉€常值的或:IPC_NOWAIT~如果沒有滿足條件的消息,調(diào)用立即返回;IPC_EXCEPT~與msgtyp>0配合使用,返回隊列中第一個類型不為msgtyp的消息;IPC_NOERROR~如果隊列中滿足條件的消息內(nèi)容大于所請求的msgsz字節(jié),則把該消息截斷,截斷部分將丟失。Msgflg=0時,msgsnd()及msgrcv()在隊列呈滿或呈空的情形時,采取阻塞等待的處理模式83從消息隊列中讀取一個消息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消息隊列控制msgctl()*intmsgctl(intmsqid,intcmd,structmsqid_ds*buf);
調(diào)用返回:成功返回0,否則返回-1。cmd操作,共有三種cmd操作IPC_STAT、IPC_SET、IPC_RMID。IPC_STAT:該命令用來獲取消息隊列信息,返回的信息存貯在buf指向的msqid結(jié)構(gòu)中;IPC_SET:該命令用來設(shè)置消息隊列的屬性,要設(shè)置的屬性存儲在buf指向的msqid結(jié)構(gòu)中;可設(shè)置屬性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同時,也影響msg_ctime成員。IPC_RMID:刪除msqid標(biāo)識的消息隊列;
85范例:刪除消息隊列*msgctl(mqid,IPC_RMID,NULL);867.3消息隊列例7.8**:設(shè)計一個程序,要求創(chuàng)建消息隊列,輸入的文字添加到消息隊列后,讀取隊列中的消息輸出。源程序代碼:8788由此例可知,進(jìn)程間通過消息隊列通信,主要是創(chuàng)建或打開消息隊列、添加消息、讀取消息和控制消息隊列這四種操作。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);}實例**
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,采用消息隊列操作編寫簡易聊天程序。作業(yè)FIFO和消息隊列機(jī)制的對比分析7.4共享內(nèi)存93Linux中進(jìn)程間通信進(jìn)程1進(jìn)程2管道pipesignal消息隊列共享內(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)存中一段存儲區(qū)多個進(jìn)程共享此存儲區(qū)特點*最快的IPC方式信息量大數(shù)據(jù)可維持共享內(nèi)存原理示意圖96≈≈二、共享內(nèi)存操作步驟*≈≈創(chuàng)建共享內(nèi)存或打開映射共享內(nèi)存讀/寫操作共享內(nèi)存解除共享內(nèi)存映射控制共享內(nèi)存(刪除)97≈≈二、共享內(nèi)存操作步驟*≈≈創(chuàng)建共享內(nèi)存或打開(已有的shm)映射共享內(nèi)存讀/寫操作共享內(nèi)存解除共享內(nèi)存映射控制共享內(nèi)存(刪除)98三、共享內(nèi)存API*創(chuàng)建共享內(nèi)存~shmget()用來獲得共享內(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()實現(xiàn)對共享內(nèi)存區(qū)域的控制操作(刪除)。99三、共享內(nèi)存API(1)—創(chuàng)建* #include<sys/ipc.h>#include<sys/shm.h>intshmget(key_tkey,size_tsize,intshmflg)參數(shù):名字(key):ftok()或整形數(shù)大小(size):字節(jié)為單位訪問方式(shmflg):讀、寫,etc.訪問權(quán)限:所有者、同組用戶、其他用戶(UGO)如,0644(同組和其他用戶只讀)可與IPC_CREAT進(jìn)行邏輯或,表示創(chuàng)建新的共享內(nèi)存或讀取已有的共享內(nèi)存IPC_CREATE:表明要創(chuàng)建新的共享內(nèi)存空間。IPC_EXCL:只有在共享內(nèi)存不存在的時候,新的共享內(nèi)存才建立,否則就產(chǎn)生錯誤。IPC_EXEL標(biāo)志本身并沒有太大的意義,但是和IPC_CREAT標(biāo)志一起使用可以用來保證所得的對象是新建的,而不是打開已有的對象。返回:標(biāo)識(ID)
100intshmget(key_tkey,size_tsize,intshmflg)成功返回共享內(nèi)存的標(biāo)識符;不成功返回-1,errno儲存錯誤原因。EINVAL
參數(shù)size小于SHMMIN或大于SHMMAX。EEXIST
預(yù)建立key所致的共享內(nèi)存,但已經(jīng)存在。EIDRM
參數(shù)key所致的共享內(nèi)存已經(jīng)刪除。ENOSPC
超過了系統(tǒng)允許建立的共享內(nèi)存的最大值 (SHMALL)。ENOENT
參數(shù)key所指的共享內(nèi)存不存在,參數(shù)shmflg 也未設(shè)IPC_CREAT位。EACCES
沒有權(quán)限。ENOMEM
核心內(nèi)存不足。
注:perror(“操作”)的執(zhí)行后將以errno(錯誤代碼)的值來決定輸出的字符串。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:訪問方式。
0~可讀寫;
SHM_RDONLY~只讀(即使已設(shè)置了寫的權(quán)限)103三、共享內(nèi)存API(2)—映射*shmat()函數(shù)返回值成功~返回共享內(nèi)存的首地址失敗~返回-1(錯誤原因存于errno中);錯誤代碼:EACCES:對于所請求的連上類型,進(jìn)程沒有足夠的權(quán)限,并且不具有CAP_IPC_OWNER權(quán)能EINVAL:參數(shù)無效
ENOMEM:內(nèi)存不足,無法分配描述詞或頁表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)程對共享內(nèi)存區(qū)域的連接。 *進(jìn)程結(jié)束時,脫離共享內(nèi)存。Shmaddr~由smat()返回的共享內(nèi)存地址。返回值0~成功,-1~失敗(錯誤原因存于errno中)106共享內(nèi)存API(4)—刪除*intshmctl(intshmqid,intcmd,structshmid_ds*buf);返回值:0成功,-1錯誤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;/*最后一個進(jìn)程連接到該段的時間*/time_tshm_dtime;/*最后一個進(jìn)程脫離該段的時間*/time_tshm_ctime;/*最后一次修改這個結(jié)構(gòu)的時間*/unsignedshortshm_cpid;/*創(chuàng)建該段進(jìn)程的pid*/unsignedshortshm_lpid;/*在該段上操作的最后一個進(jìn)程的pid*/shortshm_nattch;/*當(dāng)前連接到該段的進(jìn)程的個數(shù)*/ unsignedshortshm_npages;/*段的大小(以頁為單位)*/unsignedlong*shm_pages;/*指向frames->SHMMAX的指針數(shù)組*/structvm_area_struct*attaches;/*對共享段的描述*/};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)存的讀寫***#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)存寫共享內(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); /*在該段上操作的最后一個進(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)存實例**分別編寫兩個程序,完成共享內(nèi)存的讀與寫操作。要求: 待寫入的數(shù)據(jù)為隨機(jī)浮點數(shù); 每隔一秒采集一次不同通道(共8個),并寫入共享內(nèi)存;
循環(huán)寫入無限次;
ctl_c退出程序。
通道選擇開關(guān)1N0IN1IN2IN3IN4IN5IN6IN7ABC收發(fā)進(jìn)程1115共享內(nèi)存實例**數(shù)據(jù)結(jié)構(gòu)定義typedefstruct{ intch; /*通道號*/ doublepower;/*被測數(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ī)浮點數(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)信號量**在多用戶、多任務(wù)系統(tǒng)中,對某一資源排他操作信號量提供對進(jìn)程間共享資源訪問控制機(jī)制,相當(dāng)于內(nèi)存中的標(biāo)志。進(jìn)程可以根據(jù)它判定是否能夠訪問某些共享資源,同時,進(jìn)程也可以修改該標(biāo)志。除了用于訪問控制外,還可用于進(jìn)程同步。共享資源(M/IO)122信號量**信號量對臨界段操作,需要確保只有一個進(jìn)程獨占P(sv)操作若sv>0則sv-1,若sv=0則讓進(jìn)程暫停,等待對共享資源的操作V(sv)操作如果有等待對共享資源的操作的進(jìn)程,即等待Sv>0,則該進(jìn)程繼續(xù)執(zhí)行。如果沒有等待進(jìn)程,則sv+1臨界有效(空閑)時,sv=true(>0),執(zhí)行P(sv)操作,使得sv變?yōu)閒alse,臨界忙臨界無效(忙)時,V(sv),sv=true123信號量API
**信號量操作UNIX采用信號量數(shù)組打開或創(chuàng)建信號量semget()
信號量值操作semop()獲得或設(shè)置信號量屬性semctl()
124信號量的創(chuàng)建*#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>Intsemget(Key_tkey,intnum_sems,intsem_flags)功能:創(chuàng)建一個新的信號量,或者獲取一個已存在的信號量ID。類似于文件打開操作,返回類似于文件描述符的值,信號量描述符。返回值: 成功~非零值(>0),失敗~-1參數(shù)說明:key~標(biāo)識信號量資源。與文件名類似。用于不同的進(jìn)程間使用同一個信號量的Key;Num_sems:信號量個數(shù)。對于一個資源,常定義為1;Sem_flags:信號量訪問權(quán)限,如,IPC_CREAT|0666125范例:信號量**intopenSemId(key_tkey){intsemid; semid=semget(key,1,IPC_CREAT|0666);if(semid==-1){ perror("semget");return-1;}returnsemid;}126*信號量控制int
semctl(int
semid,int
semnum,int
cmd,union
semun
arg);功能:對信號量進(jìn)行一系列的控制。Semid~要操作的信號描述符Semnum~信號的個數(shù)(0:代表1個信號量)信號量是數(shù)組。Cmd~操作的命令.經(jīng)常用的兩個值是:SETVAL(設(shè)置信號量的初值)IPC_RMID(刪除信號量).arg是一個給cmd的參數(shù).unionsemun{ intval; structsemid_ds*buf; unsignedshort*arry;}127范例:信號量初始化**intsetSemvalue(intsemid){ unionsemunsemUnion; semUnion.val=1; if(semctl(semid,0,SETVAL,semUnion)==-1)return-1; return1;}128范例:信號量操作—刪除操作**intdelSemaphore(intsemid){ if(semctl(semid,0,IPC_RMID)==-1){ perror("semctlIPC_RMID"); return-1; } return1;}129信號量操作(P、V)intsemop(intsemid,structsembuf*semops,unsignednsops);功能: 改變信號量值。參數(shù):semid~semget()的返回值,信號量的描述符;Sops~指向一個結(jié)構(gòu)體數(shù)組的指針; structsembuf{ shortsem_num; //=0(代表第一個信號量) shortsem_op; //(-1,1)p,v shortsem_flg; //SEM_UNDO }nsops~sops結(jié)構(gòu)體數(shù)組的個數(shù),一般設(shè)為1。
130*structsembuf{ shortsem_num;//=0(代表第一個信號量) shortsem_op; //(-1,1)p,v shortsem_flg; //SEM_UNDO }Sem_num:欲處理的信號編號,0代表第一個信號量sem_op:-1:對資源加鎖(P操作)+1:對資源解鎖(V操作)sem_flg=SEM_UNDO表示進(jìn)程沒有釋放信號量而終止的時候,系統(tǒng)自動釋放該進(jìn)程所使用的信號量。131范例:信號量操作—P操作**intlockShrMem(intsemId){structsembufsops;sops.sem_num=0;sops.s
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024-2025學(xué)年新教材高中歷史第三單元遼宋夏金多民族政權(quán)的并立與元朝的統(tǒng)一第11課遼宋夏金元的經(jīng)濟(jì)與社會梯度作業(yè)含解析新人教版必修中外歷史綱要上
- 2025樣板間裝修合同書格式模板
- 2025年長沙貨運從業(yè)資格證考試題目及答案大全
- 2025年貴陽貨運從業(yè)資格證考試題目和答案
- 2025年南昌模擬考貨運從業(yè)資格
- 中國承接導(dǎo)軌項目投資可行性研究報告
- 上海現(xiàn)代化工職業(yè)學(xué)院《通訊數(shù)據(jù)獲取與分析》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025土石方運輸合同范文
- 2025設(shè)計委托合同
- 上海思博職業(yè)技術(shù)學(xué)院《嵌入式應(yīng)用開發(fā)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2024年初級應(yīng)急救援員理論考試復(fù)習(xí)題庫(含答案)
- 行政案例分析-第一次形成性考核-國開(SC)-參考資料
- 2024年度標(biāo)準(zhǔn)化消防設(shè)施保養(yǎng)協(xié)議版B版
- 《紅色江西贛土地》課件
- 消防火災(zāi)自動報警主機(jī)更換增加綜合施工專題方案
- 2024年度北京租大客車旅游租車合同范本
- 形式邏輯金岳霖課后習(xí)題答案
- 2024新反洗錢法學(xué)習(xí)課件
- 2024年新疆區(qū)公務(wù)員錄用考試《行測》真題及答案解析
- 《數(shù)字營銷》全套教學(xué)課件
- 中國特色社會主義理論與實踐研究學(xué)習(xí)通超星期末考試答案章節(jié)答案2024年
評論
0/150
提交評論