GNU PID
多進(jìn)程編程
寫在前面的話本文主要根據(jù)本人在UNIX系統(tǒng)上的編程實(shí)踐經(jīng)驗(yàn)總結(jié)而成, 既做為自己在
一個(gè)時(shí)期內(nèi)編程實(shí)踐的部分總結(jié), 又可成為文章發(fā)表. 對(duì)UNIX程序員初學(xué)者來(lái)
說(shuō)是一個(gè)小小的經(jīng)驗(yàn), 僅供參考; 對(duì)UNIX老手來(lái)說(shuō)則不值一哂, 請(qǐng)各位多多指
教.
一.多進(jìn)程程序的特點(diǎn)由于UNIX系統(tǒng)是分時(shí)多用戶系統(tǒng), CPU按時(shí)間片分配給各個(gè)用戶使用, 而在
實(shí)質(zhì)上應(yīng)該說(shuō)CPU按時(shí)間片分配給各個(gè)進(jìn)程使用, 每個(gè)進(jìn)程都有自己的運(yùn)行環(huán)境
以使得在CPU做進(jìn)程切換時(shí)不會(huì)"忘記"該進(jìn)程已計(jì)算了一半的"半成品". 以DOS
的概念來(lái)說(shuō), 進(jìn)程的切換都是一次"DOS中斷"處理過(guò)程, 包括三個(gè)層次:(1)用戶數(shù)據(jù)的保存: 包括正文段(TEXT), 數(shù)據(jù)段(DATA,BSS), 棧段(STACK), 共享內(nèi)存段(SHARED MEMORY)的保存.(2)寄存器數(shù)據(jù)的保存: 包括PC(program counter,指向下一條要執(zhí)行的指令的地址), PSW(processor status word,處理機(jī)狀態(tài)字), SP(stackpointer,棧指針), PCBP(pointer of process control block,進(jìn)程控制塊指針), FP(frame pointer,指向棧中一個(gè)函數(shù)的local變量的首地址), AP(augument pointer,指向棧中函數(shù)調(diào)用的實(shí)參位置), ISP(interrupt stack pointer,中斷棧指針), 以及其他的通用寄存器等.(3)系統(tǒng)層次的保存: 包括proc,u,虛擬存儲(chǔ)空間管理表格,中斷處理?xiàng)?
以便于該進(jìn)程再一次得到CPU時(shí)間片時(shí)能正常運(yùn)行下去.既然系統(tǒng)已經(jīng)處理好所有這些中斷處理的過(guò)程, 我們做程序還有什么要擔(dān)
心的呢? 我們盡可以使用系統(tǒng)提供的多進(jìn)程的特點(diǎn), 讓幾個(gè)程序精誠(chéng)合作, 簡(jiǎn)
單而又高效地把結(jié)果給它搞出來(lái).另外,UNIX系統(tǒng)本身也是用C語(yǔ)言寫的多進(jìn)程程序,多進(jìn)程編程是UNIX的特
點(diǎn),當(dāng)我們熟悉了多進(jìn)程編程后,將會(huì)對(duì)UNIX系統(tǒng)機(jī)制有一個(gè)較深的認(rèn)識(shí).首先我介紹一下多進(jìn)程程序的一些突出的特點(diǎn):1.并行化一件復(fù)雜的事件是可以分解成若干個(gè)簡(jiǎn)單事件來(lái)解決的, 這在程序員的大腦中早就形成了這種概念, 首先將問(wèn)題分解成一個(gè)個(gè)小問(wèn)題, 將小問(wèn)題再細(xì)分, 最后在一個(gè)合適的規(guī)模上做成一個(gè)函數(shù). 在軟件工程中也是這么說(shuō)的. 如果我們以圖的方式來(lái)思考, 一些小問(wèn)題的計(jì)算是可以互不干擾的, 可以同時(shí)處理, 而在關(guān)鍵點(diǎn)則需要統(tǒng)一在一個(gè)地方來(lái)處理, 這樣程序的運(yùn)行就是并行的, 至少?gòu)娜说臅r(shí)間觀念上來(lái)說(shuō)是這樣的. 而每個(gè)小問(wèn)題的計(jì)算又是較簡(jiǎn)單的.2.簡(jiǎn)單有序這樣的程序?qū)Τ绦騿T來(lái)說(shuō)不亞于管理一班人, 程序員為每個(gè)進(jìn)程設(shè)計(jì)好相應(yīng)的功能, 并通過(guò)一定的通訊機(jī)制將它們有機(jī)地結(jié)合在一起, 對(duì)每個(gè)進(jìn)程的設(shè)計(jì)是簡(jiǎn)單的, 只在總控部分小心應(yīng)付(其實(shí)也是蠻簡(jiǎn)單的), 就可完成整個(gè)程序的施工.3.互不干擾這個(gè)特點(diǎn)是操作系統(tǒng)的特點(diǎn), 各個(gè)進(jìn)程是獨(dú)立的, 不會(huì)串位.4.事務(wù)化比如在一個(gè)數(shù)據(jù)電話查詢系統(tǒng)中, 將程序設(shè)計(jì)成一個(gè)進(jìn)程只處理一次查詢即可, 即完成一個(gè)事務(wù). 當(dāng)電話查詢開(kāi)始時(shí), 產(chǎn)生這樣一個(gè)進(jìn)程對(duì)付這次查詢; 另一個(gè)電話進(jìn)來(lái)時(shí), 主控程序又產(chǎn)生一個(gè)這樣的進(jìn)程對(duì)付, 每個(gè)進(jìn)程完成查詢?nèi)蝿?wù)后消失. 這樣的編程多簡(jiǎn)單, 只要做一次查詢的程序就可以了.
二.常用的多進(jìn)程編程的系統(tǒng)調(diào)用1.fork()功能:創(chuàng)建一個(gè)新的進(jìn)程.語(yǔ)法:#include <unistd.h>#include <sys/types.h>pid_t fork();
說(shuō)明:本系統(tǒng)調(diào)用產(chǎn)生一個(gè)新的進(jìn)程, 叫子進(jìn)程, 是調(diào)用進(jìn)程的一個(gè)復(fù)制品. 調(diào)用進(jìn)程叫父進(jìn)程, 子進(jìn)程繼承了父進(jìn)程的幾乎所有的屬性:. 實(shí)際UID,GID和有效UID,GID.. 環(huán)境變量.. 附加GID.. 調(diào)用exec()時(shí)的關(guān)閉標(biāo)志.. UID設(shè)置模式比特位.. GID設(shè)置模式比特位.. 進(jìn)程組號(hào).. 會(huì)話ID.. 控制終端.. 當(dāng)前工作目錄.. 根目錄.. 文件創(chuàng)建掩碼UMASK.. 文件長(zhǎng)度限制ULIMIT.. 預(yù)定值, 如優(yōu)先級(jí)和任何其他的進(jìn)程預(yù)定參數(shù), 根據(jù)種類不同決定是否可以繼承.. 還有一些其它屬性.但子進(jìn)程也有與父進(jìn)程不同的屬性:. 進(jìn)程號(hào), 子進(jìn)程號(hào)不同與任何一個(gè)活動(dòng)的進(jìn)程組號(hào).. 父進(jìn)程號(hào).. 子進(jìn)程繼承父進(jìn)程的文件描述符或流時(shí), 具有自己的一個(gè)拷貝并且與父進(jìn)程和其它子進(jìn)程共享該資源.. 子進(jìn)程的用戶時(shí)間和系統(tǒng)時(shí)間被初始化為0.. 子進(jìn)程的超時(shí)時(shí)鐘設(shè)置為0.. 子進(jìn)程的信號(hào)處理函數(shù)指針組置為空.. 子進(jìn)程不繼承父進(jìn)程的記錄鎖.返回值: 調(diào)用成功則對(duì)子進(jìn)程返回0, 對(duì)父進(jìn)程返回子進(jìn)程號(hào), 這也是最方便的區(qū)分父子進(jìn)程的方法. 若調(diào)用失敗則返回-1給父進(jìn)程,子進(jìn)程不生成.例子:pid_t pid;
if ((pid=fork())>0) {/*父進(jìn)程處理過(guò)程*/}else if (pid==0) {/*子進(jìn)程處理過(guò)程*/exit(0); /*注意子進(jìn)程必須用exit()退出運(yùn)行*/
}else {printf("fork error\n");
exit(0);
}2.system()功能:產(chǎn)生一個(gè)新的進(jìn)程, 子進(jìn)程執(zhí)行指定的命令.語(yǔ)法:#include <stdio.h>#include <stdlib.h>int system(string)char *string;
說(shuō)明:本調(diào)用將參數(shù)string傳遞給一個(gè)命令解釋器(一般為sh)執(zhí)行, 即string被解釋為一條命令, 由sh執(zhí)行該命令.若參數(shù)string為一個(gè)空指針則為檢查命令解釋器是否存在.該命令可以同命令行命令相同形式, 但由于命令做為一個(gè)參數(shù)放在系統(tǒng)調(diào)用中, 應(yīng)注意編譯時(shí)對(duì)特殊意義字符的處理. 命令的查找是按PATH環(huán)境變量的定義的. 命令所生成的后果一般不會(huì)對(duì)父進(jìn)程造成影響.返回值:當(dāng)參數(shù)為空指針時(shí), 只有當(dāng)命令解釋器有效時(shí)返回值為非零.若參數(shù)不為空指針, 返回值為該命令的返回狀態(tài)(同waitpid())的返回值. 命令無(wú)效或語(yǔ)法錯(cuò)誤則返回非零值,所執(zhí)行的命令被終止. 其他情況則返回-1.例子:char command[81];
int i;
for (i=1;i<8;i++) {sprintf(command,"ps -t tty%02i",i);
system(command);
}3.exec()功能:執(zhí)行一個(gè)文件語(yǔ)法:#include <unistd.h>int execl(path,arg0,...,argn,(char*)0)char *path,*arg0,...,*argn;
int execv(path,argv)char *path,*argv[];
int execle(path,arg0,...,argn,(char*)0,envp)char *path,*arg0,...,*argn,*envp[];
int execve(path,argv,envp)char *path,*argv[],*envp[];
int execvp(file,argv)char *file,*argv[];
說(shuō)明:這是一個(gè)系統(tǒng)調(diào)用族, 用于將一個(gè)新的程序調(diào)入本進(jìn)程所占的內(nèi)存, 并覆蓋之, 產(chǎn)生新的內(nèi)存進(jìn)程映象. 新的程序可以是可執(zhí)行文件或SHELL批命令.當(dāng)C程序被執(zhí)行時(shí),是如下調(diào)用的:main(int argc,char *argv[],char *envp[]);
argc是參數(shù)個(gè)數(shù),是各個(gè)參數(shù)字符串指針數(shù)組,envp是新進(jìn)程的環(huán)境變量字符串的指針數(shù)組.argc至少為1,argv[0]為程序文件名,所以,在上面的exec系統(tǒng)調(diào)用族中,path為新進(jìn)程文件的路徑名,file為新進(jìn)程文件名,若file不是全路徑名,系統(tǒng)調(diào)用會(huì)按PATH環(huán)境變量自動(dòng)找對(duì)應(yīng)的可執(zhí)行文件運(yùn)行.若新進(jìn)程文件不是一個(gè)可執(zhí)行的目標(biāo)文件(如批處理文件),則execlp()和execvp()會(huì)將該文件內(nèi)容作為一個(gè)命令解釋器的標(biāo)準(zhǔn)輸入形成system().arg0,...等指針指向'\0'結(jié)束的字符串,組成新進(jìn)程的有效參數(shù),且該參數(shù)列表以一個(gè)空指針結(jié)束.反過(guò)來(lái),arg0至少必須存在并指向新進(jìn)程文件名或路徑名.同樣,argv是字符串指針數(shù)組,argv[0]指向新進(jìn)程文件名或路徑名,并以一空指針結(jié)束.envp是一個(gè)字符串指針數(shù)組,以空指針結(jié)束,這些字符串組成新進(jìn)程的環(huán)境.在調(diào)用這些系統(tǒng)調(diào)用前打開(kāi)的文件指針對(duì)新進(jìn)程來(lái)說(shuō)也是打開(kāi)的,除非它已定義了close-on-exec標(biāo)志.打開(kāi)的文件指針在新進(jìn)程中保持不變,所有相關(guān)的文件鎖也被保留.調(diào)用進(jìn)程設(shè)置并正被捕俘的信號(hào)在新進(jìn)程中被恢復(fù)為缺省設(shè)置,其它的則保持不變.新進(jìn)程啟動(dòng)時(shí)按文件的SUID和SGID設(shè)置定義文件的UID和GID為有效UID和GID.新進(jìn)程還繼承了如下屬性:. 附加GID.. 進(jìn)程號(hào).. 父進(jìn)程號(hào).. 進(jìn)程組號(hào).. 會(huì)話號(hào).. 控制終端.. alarm時(shí)鐘信號(hào)剩下的時(shí)間.. 當(dāng)前工作目錄.. 根目錄.. 文件創(chuàng)建掩碼.. 資源限制.. 用戶時(shí)間,系統(tǒng)時(shí)間,子進(jìn)程用戶時(shí)間,子進(jìn)程系統(tǒng)時(shí)間.. 記錄鎖.. 進(jìn)程信號(hào)掩碼.. 信號(hào)屏蔽.. 優(yōu)先級(jí).. 預(yù)定值.調(diào)用成功后,系統(tǒng)調(diào)用修改新進(jìn)程文件的最新訪問(wèn)時(shí)間.返回值:該系統(tǒng)調(diào)用一般不會(huì)有成功返回值, 因?yàn)樵瓉?lái)的進(jìn)程已蕩然無(wú)存.例子:printf("now this process will be ps command\n");
execl("/bin/ps","ps","-ef",NULL);
4.popen()功能:初始化從/到一個(gè)進(jìn)程的管道.語(yǔ)法:#include <stdio.h>FILE *popen(command,type)char *command,type;
說(shuō)明:本系統(tǒng)調(diào)用在調(diào)用進(jìn)程和被執(zhí)行命令間創(chuàng)建一個(gè)管道.參數(shù)command做為被執(zhí)行的命令行.type做為I/O模式,"r"為從被執(zhí)行命令讀,"w"為向被執(zhí)行命令寫.返回一個(gè)標(biāo)準(zhǔn)流指針,做為管道描述符,向被執(zhí)行命令讀或?qū)憯?shù)據(jù)(做為被執(zhí)行命令的STDIN或STDOUT)該系統(tǒng)調(diào)用可以用來(lái)在程序中調(diào)用系統(tǒng)命令,并取得命令的輸出信息或者向命令輸入信息.返回值:不成功則返回NULL,成功則返回管道的文件指針.5.pclose()功能:關(guān)閉到一個(gè)進(jìn)程的管道.語(yǔ)法:#include <stdio.h>int pclose(strm)FILE *strm;
說(shuō)明:本系統(tǒng)調(diào)用用于關(guān)閉由popen()打開(kāi)的管道,并會(huì)等待由popen()激活的命令執(zhí)行結(jié)束后,關(guān)閉管道后讀取命令返回碼.返回值:若關(guān)閉的文件描述符不是由popen()打開(kāi)的,則返回-1.例子:printf("now this process will call popen system call\n");
FILE * fd;
if ((fd=popen("ps -ef","r"))==NULL) {printf("call popen failed\n");
return;
}else {char str[80];
while (fgets(str,80,fd)!=NULL)printf("%s\n",str);
}pclose(fd);
6.wait()功能:等待一個(gè)子進(jìn)程返回并修改狀態(tài)語(yǔ)法:#include <sys/types.h>#include <sys/wait.h>pid_t wait(stat_loc)int *stat_loc;
說(shuō)明:允許調(diào)用進(jìn)程取得子進(jìn)程的狀態(tài)信息.調(diào)用進(jìn)程將會(huì)掛起直到其一個(gè)子進(jìn)程終止.返回值:等待到一個(gè)子進(jìn)程返回時(shí),返回值為該子進(jìn)程號(hào),否則返回值為-1.同時(shí)stat_loc返回子進(jìn)程的返回值.例子:/*父進(jìn)程*/if (fork()>0) {wait((int *)0);
/*父進(jìn)程等待子進(jìn)程的返回*/}else {/*子進(jìn)程處理過(guò)程*/exit(0);
}7.waitpid()功能:等待指定進(jìn)程號(hào)的子進(jìn)程的返回并修改狀態(tài)語(yǔ)法:#include <sys/types.h>#include <sys/wait.h>pid_t waitpid(pid,stat_loc,options)pid_t pid;
int *stat_loc,options;
說(shuō)明:當(dāng)pid等于-1,options等于0時(shí),該系統(tǒng)調(diào)用等同于wait().否則該系統(tǒng)調(diào)用的行為由參數(shù)pid和options決定.pid指定了一組父進(jìn)程要求知道其狀態(tài)的子進(jìn)程:-1:要求知道任何一個(gè)子進(jìn)程的返回狀態(tài).>0:要求知道進(jìn)程號(hào)為pid值的子進(jìn)程的狀態(tài).<-1:要求知道進(jìn)程組號(hào)為pid的絕對(duì)值的子進(jìn)程的狀態(tài).options參數(shù)為以比特方式表示的標(biāo)志以或運(yùn)算組成的位圖,每個(gè)標(biāo)志以字節(jié)中某個(gè)比特置1表示:WUNTRACED:報(bào)告任何未知而又已停止運(yùn)行的指定進(jìn)程號(hào)的子進(jìn)程的狀態(tài).該子進(jìn)程的狀態(tài)自停止運(yùn)行時(shí)起就沒(méi)有被報(bào)告過(guò).WCONTINUED:報(bào)告任何繼續(xù)運(yùn)行的指定進(jìn)程號(hào)的子進(jìn)程的狀態(tài),該子進(jìn)程的狀態(tài)自繼續(xù)運(yùn)行起就沒(méi)有被報(bào)告過(guò).WHOHANG:若調(diào)用本系統(tǒng)調(diào)用時(shí),指定進(jìn)程號(hào)的子進(jìn)程的狀態(tài)目前并不是立即有效的(即可被立即讀取的),調(diào)用進(jìn)程并被暫停執(zhí)行.WNOWAIT:保持將其狀態(tài)設(shè)置在stat_loc的進(jìn)程在可等待狀態(tài).該進(jìn)程將等待直到下次被要求其返回狀態(tài)值.返回值:等待到一個(gè)子進(jìn)程返回時(shí),返回值為該子進(jìn)程號(hào),否則返回值為-1.同時(shí)stat_loc返回子進(jìn)程的返回值.例子:pid_t pid;
int stat_loc;
/*父進(jìn)程*/if ((pid=fork())>0) {waitpid(pid,&stat_loc,0);
/*父進(jìn)程等待進(jìn)程號(hào)為pid的子進(jìn)程的返回*/}else {/*子進(jìn)程的處理過(guò)程*/exit(1);
}/*父進(jìn)程*/printf("stat_loc is [%d]\n",stat_loc);
/*字符串"stat_loc is [1]"將被打印出來(lái)*/8.setpgrp()功能:設(shè)置進(jìn)程組號(hào)和會(huì)話號(hào).語(yǔ)法:#include <sys/types.h>pid_t setpgrp()說(shuō)明:若調(diào)用進(jìn)程不是會(huì)話首進(jìn)程.將進(jìn)程組號(hào)和會(huì)話號(hào)都設(shè)置為與它的進(jìn)程號(hào)相等.并釋放調(diào)用進(jìn)程的控制終端.返回值:調(diào)用成功后,返回新的進(jìn)程組號(hào).例子:/*父進(jìn)程處理*/if (fork()>0) {/*父進(jìn)程處理*/}else {setpgrp();
/*子進(jìn)程的進(jìn)程組號(hào)已修改成與它的進(jìn)程號(hào)相同*/exit(0);
}9.exit()功能:終止進(jìn)程.語(yǔ)法:#include <stdlib.h>void exit(status)int status;
說(shuō)明:調(diào)用進(jìn)程被該系統(tǒng)調(diào)用終止.引起附加的處理在進(jìn)程被終止前全部結(jié)束.返回值:無(wú)10.signal()功能:信號(hào)管理功能語(yǔ)法:#include <signal.h>void (*signal(sig,disp))(int)int sig;
void (*disp)(int);
void (*sigset(sig,disp))(int)int sig;
void (*disp)(int);
int sighold(sig)int sig;
int sigrelse(sig)int sig;
int sigignore(sig)int sig;
int sigpause(sig)int sig;
說(shuō)明:這些系統(tǒng)調(diào)用提供了應(yīng)用程序?qū)χ付ㄐ盘?hào)的簡(jiǎn)單的信號(hào)處理.signal()和sigset()用于修改信號(hào)定位.參數(shù)sig指定信號(hào)(除了SIGKILL和SIGSTOP,這兩種信號(hào)由系統(tǒng)處理,用戶程序不能捕捉到).disp指定新的信號(hào)定位,即新的信號(hào)處理函數(shù)指針.可以為SIG_IGN,SIG_DFL或信號(hào)句柄地址.若使用signal(),disp是信號(hào)句柄地址,sig不能為SIGILL,SIGTRAP或SIGPWR,收到該信號(hào)時(shí),系統(tǒng)首先將重置sig的信號(hào)句柄為SIG_DFL,然后執(zhí)行信號(hào)句柄.若使用sigset(),disp是信號(hào)句柄地址,該信號(hào)時(shí),系統(tǒng)首先將該信號(hào)加入調(diào)用進(jìn)程的信號(hào)掩碼中,然后執(zhí)行信號(hào)句柄.當(dāng)信號(hào)句柄運(yùn)行結(jié)束后,系統(tǒng)將恢復(fù)調(diào)用進(jìn)程的信號(hào)掩碼為信號(hào)收到前的狀態(tài).另外,使用sigset()時(shí),disp為SIG_HOLD,則該信號(hào)將會(huì)加入調(diào)用進(jìn)程的信號(hào)掩碼中而信號(hào)的定位不變.sighold()將信號(hào)加入調(diào)用進(jìn)程的信號(hào)掩碼中.sigrelse()將信號(hào)從調(diào)用進(jìn)程的信號(hào)掩碼中刪除.sigignore()將信號(hào)的定位設(shè)置為SIG_IGN.sigpause()將信號(hào)從調(diào)用進(jìn)程的信號(hào)掩碼中刪除,同時(shí)掛起調(diào)用進(jìn)程直到收到信號(hào).若信號(hào)SIGCHLD的信號(hào)定位為SIG_IGN,則調(diào)用進(jìn)程的子進(jìn)程在終止時(shí)不會(huì)變成僵死進(jìn)程.調(diào)用進(jìn)程也不用等待子進(jìn)程返回并做相應(yīng)處理.返回值:調(diào)用成功則signal()返回最近調(diào)用signal()設(shè)置的disp的值.否則返回SIG_ERR.例子一:設(shè)置用戶自己的信號(hào)中斷處理函數(shù),以SIGINT信號(hào)為例:int flag=0;
void myself(){flag=1;
printf("get signal SIGINT\n");
/*若要重新設(shè)置SIGINT信號(hào)中斷處理函數(shù)為本函數(shù)則執(zhí)行以*下步驟*/void (*a)();
a=myself;
signal(SIGINT,a);
flag=2;
}main(){while (1) {sleep(2000); /*等待中斷信號(hào)*/if (flag==1) {printf("skip system call sleep\n");
exit(0);
}if (flag==2) {printf("skip system call sleep\n");
printf("waiting for next signal\n");
}}}11.kill()功能:向一個(gè)或一組進(jìn)程發(fā)送一個(gè)信號(hào).語(yǔ)法:#include <sys/types.h>#include <signal.h>int kill(pid,sig);
pid_t pid;
int sig;
說(shuō)明:本系統(tǒng)調(diào)用向一個(gè)或一組進(jìn)程發(fā)送一個(gè)信號(hào),該信號(hào)由參數(shù)sig指定,為系統(tǒng)給出的信號(hào)表中的一個(gè).若為0(空信號(hào))則檢查錯(cuò)誤但實(shí)際上并沒(méi)有發(fā)送信號(hào),用于檢查pid的有效性.pid指定將要被發(fā)送信號(hào)的進(jìn)程或進(jìn)程組.pid若大于0,則信號(hào)將被發(fā)送到進(jìn)程號(hào)等于pid的進(jìn)程;若pid等于0則信號(hào)將被發(fā)送到所
有的與發(fā)送信號(hào)進(jìn)程同在一個(gè)進(jìn)程組的進(jìn)程(系統(tǒng)的特殊進(jìn)程除外);若pid小于-1,則信號(hào)將被發(fā)送到所有進(jìn)程組號(hào)與pid絕對(duì)值相同的進(jìn)程;若pid等于-1,則信號(hào)將被發(fā)送到所有的進(jìn)程(特殊系
統(tǒng)進(jìn)程除外).信號(hào)要發(fā)送到指定的進(jìn)程,首先調(diào)用進(jìn)程必須有對(duì)該進(jìn)程發(fā)送信號(hào)的權(quán)限.若調(diào)用進(jìn)程有合適的優(yōu)先級(jí)則具備有權(quán)限.若調(diào)用進(jìn)程的實(shí)際或有效的UID等于接收信號(hào)的進(jìn)程的實(shí)際UID或用setuid()系統(tǒng)調(diào)用設(shè)置的UID,或sig等于SIGCONT同時(shí)收發(fā)雙方進(jìn)程的會(huì)話號(hào)相同,則調(diào)用進(jìn)程也有發(fā)送信號(hào)的權(quán)限.若進(jìn)程有發(fā)送信號(hào)到pid指定的任何一個(gè)進(jìn)程的權(quán)限則調(diào)用成功,否則調(diào)用失敗,沒(méi)有信號(hào)發(fā)出.返回值:調(diào)用成功則返回0,否則返回-1.例子:假設(shè)前一個(gè)例子進(jìn)程號(hào)為324,現(xiàn)向它發(fā)一個(gè)SIGINT信號(hào),讓它做信號(hào)處理:kill((pid_t)324,SIGINT);
12.alarm()功能:設(shè)置一個(gè)進(jìn)程的超時(shí)時(shí)鐘.語(yǔ)法:#include <unistd.h>unsigned int alarm(sec)unsigned int sec;
說(shuō)明:指示調(diào)用進(jìn)程的超時(shí)時(shí)鐘在指定的時(shí)間后向調(diào)用進(jìn)程發(fā)送一個(gè)SIGALRM信號(hào).設(shè)置超時(shí)時(shí)鐘時(shí)時(shí)間值不會(huì)被放入堆棧中,后一次設(shè)置會(huì)把前一次(還未到超時(shí)時(shí)間)沖掉.若sec為0,則取消任何以前設(shè)置的超時(shí)時(shí)鐘.fork()會(huì)將新進(jìn)程的超時(shí)時(shí)鐘初始化為0.而當(dāng)一個(gè)進(jìn)程用exec()族系統(tǒng)調(diào)用新的執(zhí)行文件時(shí),調(diào)用前設(shè)置的超時(shí)時(shí)鐘在調(diào)用后仍有效.返回值:返回上次設(shè)置超時(shí)時(shí)鐘后到調(diào)用時(shí)還剩余的時(shí)間秒數(shù).例子:int flag=0;
void myself(){flag=1;
printf("get signal SIGALRM\n");
/*若要重新設(shè)置SIGALRM信號(hào)中斷處理函數(shù)為本函數(shù)則執(zhí)行*以下步驟*/void (*a)();
a=myself;
signal(SIGALRM,a);
flag=2;
}main(){alarm(100); /*100秒后發(fā)超時(shí)中斷信號(hào)*/while (1) {sleep(2000); /*等待中斷信號(hào)*/if (flag==1) {printf("skip system call sleep\n");
exit(0);
}if (flag==2) {printf("skip system call sleep\n");
printf("waiting for next signal\n");
}}}13.msgsnd()功能:發(fā)送消息到指定的消息隊(duì)列中.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgsnd(msqid,msgp,msgsz,msgflg)int msqid;
void *msgp;
size_t msgsz;
int msgflg;
說(shuō)明:發(fā)送一個(gè)消息到由msqid指定消息隊(duì)列標(biāo)識(shí)號(hào)的消息隊(duì)列.參數(shù)msgp指向一個(gè)用戶定義的緩沖區(qū),并且緩沖區(qū)的第一個(gè)域應(yīng)為長(zhǎng)整型,指定消息類型,其他數(shù)據(jù)放在緩沖區(qū)的消息中其他正文區(qū)內(nèi).下面是消息元素定義:long mtype;
char mtext[];
mtype是一個(gè)整數(shù),用于接收進(jìn)程選擇消息類型.mtext是一個(gè)長(zhǎng)度為msgsz字節(jié)的任何正文,參數(shù)msgsz可從0到系統(tǒng)允許的最大值間變化.msgflg指定操作行為:. 若(msgflg&IPC_NOWAIT)是真的,消息并不是被立即發(fā)送而調(diào)用進(jìn)程會(huì)立即返回.. 若(msgflg&IPC_NOWAIT)不是真的,則調(diào)用進(jìn)程會(huì)被掛起直到下面情況之一發(fā)生:* 消息被發(fā)送出去.* 消息隊(duì)列標(biāo)志被系統(tǒng)刪除.系統(tǒng)調(diào)用返回-1.* 調(diào)用進(jìn)程接收到一個(gè)未被忽略的中斷信號(hào),調(diào)用進(jìn)程繼續(xù)執(zhí)行或被終止.調(diào)用成功后,對(duì)應(yīng)指定的消息隊(duì)列的相關(guān)結(jié)構(gòu)做如下動(dòng)作:. 消息數(shù)(msg_qnum)加1.. 消息隊(duì)列最近發(fā)送進(jìn)程號(hào)(msg_lspid)改為調(diào)用進(jìn)程號(hào).. 消息隊(duì)列發(fā)送時(shí)間(msg_stime)改為當(dāng)前系統(tǒng)時(shí)間.以上信息可用命令ipcs -a看到.返回值:成功則返回0,否則返回-1.14.msgrcv()功能:從消息隊(duì)列中取得指定類型的消息.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgrcv(msqid,msgp,msgsz,msgtyp,msgflg)int msqid;
void *msgp;
int msgsz;
long msgtyp;
int msgflg;
說(shuō)明:本系統(tǒng)調(diào)用從由msqid指定的消息隊(duì)列中讀取一個(gè)由msgtyp指定類型的消息到由msgp指向的緩沖區(qū)中,同樣的,該緩沖區(qū)的結(jié)構(gòu)如前所述,包括消息類型和消息正文.msgsz為可接收的消息正文的字節(jié)數(shù).若接收到的消息正文的長(zhǎng)度大于msgsz,則會(huì)被截短到msgsz字節(jié)為止(當(dāng)消息標(biāo)志msgflg&MSG_NOERROR為真時(shí)),截掉的部份將被丟失,而且不通知消息發(fā)送進(jìn)程.msgtyp指定消息類型:. 為0則接收消息隊(duì)列中第一個(gè)消息.. 大于0則接收消息隊(duì)列中第一個(gè)類型為msgtyp的消息.. 小于0則接收消息隊(duì)列中第一個(gè)類型值不小于msgtyp絕對(duì)值且類型值又最小的消息.msgflg指定操作行為:. 若(msgflg&IPC_NOWAIT)是真的,調(diào)用進(jìn)程會(huì)立即返回,若沒(méi)有接收到消息則返回值為-1,errno設(shè)置為ENOMSG.. 若(msgflg&IPC_NOWAIT)不是真的,則調(diào)用進(jìn)程會(huì)被掛起直到下面情況之一發(fā)生:* 隊(duì)列中的消息的類型是有效的.* 消息隊(duì)列標(biāo)志被系統(tǒng)刪除.系統(tǒng)調(diào)用返回-1.* 調(diào)用進(jìn)程接收到一個(gè)未被忽略的中斷信號(hào),調(diào)用進(jìn)程繼續(xù)執(zhí)行或被終止.調(diào)用成功后,對(duì)應(yīng)指定的消息隊(duì)列的相關(guān)結(jié)構(gòu)做如下動(dòng)作:. 消息數(shù)(msg_qnum)減1.. 消息隊(duì)列最近接收進(jìn)程號(hào)(msg_lrpid)改為調(diào)用進(jìn)程號(hào).. 消息隊(duì)列接收時(shí)間(msg_rtime)改為當(dāng)前系統(tǒng)時(shí)間.以上信息可用命令ipcs -a看到.返回值:調(diào)用成功則返回值等于接收到實(shí)際消息正文的字節(jié)數(shù).不成功則返回-1.15.msgctl()功能:消息控制操作語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgctl(msqid,cmd,buf)int msqid,cmd;
struct msqid_ds *buf;
說(shuō)明:本系統(tǒng)調(diào)用提供一系列消息控制操作,操作動(dòng)作由cmd定義,以下cmd定義值表明了各操作動(dòng)作的定義.. IPC_STAT:將msqid相關(guān)的數(shù)據(jù)結(jié)構(gòu)中各個(gè)元素的當(dāng)前值放入由buf指向的結(jié)構(gòu)中.. IPC_SET:將msqid相關(guān)的數(shù)據(jù)結(jié)構(gòu)中的下列元素設(shè)置為由buf指向的結(jié)構(gòu)中的對(duì)應(yīng)值.msg_perm.uidmsg_perm.gidmsg_perm.modemsg_qbytes本命令只能由有效UID等于msg_perm.cuid或msg_perm.uid的進(jìn)程或有效UID有合適權(quán)限的進(jìn)程操作.只有具有合適權(quán)限的用戶才能增加msg_qbytes的值.. IPC_RMID:刪除由msqid指示的消息隊(duì)列.將它從系統(tǒng)中刪除并破壞相關(guān)的數(shù)據(jù)結(jié)構(gòu).本命令只能由有效UID等于msg_perm.cuid或msg_perm.uid的進(jìn)程或有效UID有合適權(quán)限的進(jìn)程操作.返回值:調(diào)用成功則返回值為0,否則為-1.16.msgget()功能:取得一個(gè)消息隊(duì)列.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key,msgflg)key_t key;
int msgflg;
說(shuō)明:本系統(tǒng)調(diào)用返回與參數(shù)key相關(guān)的消息隊(duì)列的標(biāo)識(shí)符.若以下事實(shí)成立,則與消息隊(duì)列相關(guān)的標(biāo)識(shí)符和數(shù)據(jù)結(jié)構(gòu)將被創(chuàng)建出來(lái):. 若參數(shù)key等于IPC_PRIVATE.. 若參數(shù)key沒(méi)有一個(gè)已存在的消息隊(duì)列標(biāo)識(shí)符與之相關(guān),同時(shí)值(msgflg&IPC_CREAT)為真.創(chuàng)建消息隊(duì)列時(shí),與新的消息隊(duì)列標(biāo)識(shí)符相關(guān)的數(shù)據(jù)結(jié)構(gòu)將被初始化為如下:. msg_perm.cuid和msg_perm.uid設(shè)置為調(diào)用進(jìn)程的有效UID.. msg_perm.cgid和msg_perm.gid設(shè)置為調(diào)用進(jìn)程的有效GID.. msg_perm.mode訪問(wèn)權(quán)限比特位設(shè)置為msgflg訪問(wèn)權(quán)限比特位.. msg_qnum,msg_lspid,msg_lrpid,msg_stime,msg_rtime設(shè)置為0.. msg_ctime設(shè)置為當(dāng)前系統(tǒng)時(shí)間.. msg_qbytes設(shè)置為系統(tǒng)允許的最大值.返回值:調(diào)用成功則返回一非0值,稱為消息隊(duì)列標(biāo)識(shí)符;否則返回值為-1.
例子:本例將包括上述所有消息隊(duì)列操作的系統(tǒng)調(diào)用:#define RKEY 0x9001L /*讀消息隊(duì)列的KEY值*/#define WKEY 0x9002L /*寫消息隊(duì)列的KEY值*/#define MSGFLG 0666 /*消息隊(duì)列訪問(wèn)權(quán)限*/#define IPC_WAIT 0 /*等待方式在include文件中未定義*/int rmsqid; /*讀消息隊(duì)列標(biāo)識(shí)符*/int wmsqid; /*寫消息隊(duì)列標(biāo)識(shí)符*/
struct msgbuf {long mtype;
char mtext[200];
} buf;
/*若讀消息隊(duì)列已存在就取得標(biāo)識(shí)符,否則則創(chuàng)建并取得標(biāo)識(shí)符*/if ((rmsqid=msgget(RKEY,MSGFLG|IPC_CREAT))<0) {printf("get read message queue failed\n");
exit(1);
}/*若寫消息隊(duì)列已存在則失敗,若不存在則創(chuàng)建并取得標(biāo)識(shí)符*/if ((wmsqid=msgget(WKEY,MSGFLG|IPC_CREAT|IPC_TRUNC))<0) {printf("get write message queue failed\n");
exit(2);
}/*接收所有類型的消息*/if (msgrcv(rmsqid,&buf,sizeof(struct msgbuf)-sizeof(long),0L,IPC_WAIT)>0)printf("get %ld type message from queue:%s\n",buf.mtype,buf.mtext);
else {printf("get message failed\n");
exit(3);
}buf.mtype=3Lif (msgsnd(wmsqid,&buf,sizeof(struct msgbuf)-sizeof(long),IPC_NOWAIT)>0)printf("send message OK\n");
else {printf("send message failed\n");
exit(4);
}msgctl(wmsqid,IPC_RMID,(struct msqid *)NULL);
17.shmat()功能:聯(lián)接共享內(nèi)存的操作.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>void *shmat(shmid,shmaddr,shmflg)int shmid;
void *shmaddr;
int shmid;
說(shuō)明:將由shmid指示的共享內(nèi)存聯(lián)接到調(diào)用進(jìn)程的數(shù)據(jù)段中.被聯(lián)接的段放在地址,該地址由以下準(zhǔn)則指定:. 若shmaddr等于(void *)0,則段聯(lián)接到由系統(tǒng)選擇的第一個(gè)可用的地址上.. 若shmaddr不等于(void *)0同時(shí)(shmflg&SHM_RND)值為真,則段聯(lián)接到由(shmaddr-(shmaddr%SHMLBA))給出的地址上.. 若shmaddr不等于(void *)0同時(shí)(shmflg&SHM_RND)值為假,則段聯(lián)接到由shmaddr指定的地址上.若(shmflg&sSHM_RDONLY)為真并且調(diào)用進(jìn)程有讀允許,則被聯(lián)接的段為只讀;否則,若值不為真且調(diào)用進(jìn)程有讀寫權(quán)限,則被聯(lián)接
的段為可讀寫的.返回值:若調(diào)用成功則返回被聯(lián)接的共享內(nèi)存段在數(shù)據(jù)段上的啟始地址.否則返回值為-1.18.shmdt()功能:斷開(kāi)共享內(nèi)存聯(lián)接的操作.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>void *shmdt(shmaddr)void *shmaddr;
說(shuō)明:本系統(tǒng)調(diào)用將由shmaddr指定的共享內(nèi)存段從調(diào)用進(jìn)程的數(shù)據(jù)段脫離出去.返回值:若調(diào)用成功則返回值為0,否則返回值為-1.19.shmget()功能:取得共享內(nèi)存段語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int shmget(key,size,shmflg)key_t key;
int size,shmflg;
說(shuō)明:本系統(tǒng)調(diào)用返回key相關(guān)的共享內(nèi)存標(biāo)識(shí)符.共享內(nèi)存標(biāo)識(shí)符和相關(guān)數(shù)據(jù)結(jié)構(gòu)及至少size字節(jié)的共享內(nèi)存段能正常創(chuàng)建,要求以下事實(shí)成立:. 參數(shù)key等于IPC_PRIVATE.. 參數(shù)key沒(méi)有相關(guān)的共享內(nèi)存標(biāo)識(shí)符,同時(shí)(shmflg&IPC_CREAT)值為真.共享內(nèi)存創(chuàng)建時(shí),新生成的共享內(nèi)存標(biāo)識(shí)相關(guān)的數(shù)據(jù)結(jié)構(gòu)被初始化如下:. shm_perm.cuid和shm_perm.uid設(shè)置為調(diào)用進(jìn)程的有效UID.. shm_perm.cgid和shm_perm.gid設(shè)置為調(diào)用進(jìn)程的有效GID.. shm_perm.mode訪問(wèn)權(quán)限比特位設(shè)置為shmflg訪問(wèn)權(quán)限比特位.. shm_lpid,shm_nattch,shm_atime,shm_dtime設(shè)置為0.. shm_ctime設(shè)置為當(dāng)前系統(tǒng)時(shí)間.. shm_segsz設(shè)置為0.返回值:若調(diào)用成功則返回一個(gè)非0值,稱為共享內(nèi)存標(biāo)識(shí)符,否則返回值為-1.20.shmctl()功能:共享內(nèi)存控制操作.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int shmctl(shmid,cmd,buf)int shmid,cmd;
struct shmid_ds *buf;
說(shuō)明:本系統(tǒng)調(diào)用提供一系列共享內(nèi)存控制操作.操作行為由cmd指定.以下為cmd的有效值:. IPC_STAT:將shmid相關(guān)的數(shù)據(jù)結(jié)構(gòu)中各個(gè)元素的當(dāng)前值放入由buf指向的結(jié)構(gòu)中.. IPC_SET:將shmid相關(guān)的數(shù)據(jù)結(jié)構(gòu)中的下列元素設(shè)置為由buf指向的結(jié)構(gòu)中的對(duì)應(yīng)值.shm_perm.uidshm_perm.gidshm_perm.mode本命令只能由有效UID等于shm_perm.cuid或shm_perm.uid的進(jìn)程或有效UID有合適權(quán)限的進(jìn)程操作.. IPC_RMID:刪除由shmid指示的共享內(nèi)存.將它從系統(tǒng)中刪除并破壞相關(guān)的數(shù)據(jù)結(jié)構(gòu).本命令只能由有效UID等于shm_perm.cuid或shm_perm.uid的進(jìn)程或有效UID有合適權(quán)限的進(jìn)程操作.返回值:若調(diào)用成功則返回0,否則返回-1.例子:本例包括上述所有共享內(nèi)存操作系統(tǒng)調(diào)用:#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#define SHMKEY 74#define K 1024int shmid;
cleanup(){shmctl(shmid,IPC_RMID,0);
exit(0);
}main(){int *pint;
char *addr1,*addr2;
extern char *shmat();
extern cleanup();
for (i=0;i<20;i++)signal(i,cleanup);
shmid=shmget(SHMKEY,128*K,0777|IPC_CREAT);
addr1=shmat(shmid,0,0);
addr2=shmat(shmid,0,0);
printf("addr1 0x%x addr2 0x%x\n",addr1,addr2);
pint=(int*)addr1;
for (i=0;i<256;i++)*pint++=i;
pint=(int*)addr1;
*pint=256;
pint=(int*)addr2;
for (i=0;i<256;i++)printf("index %d\tvalue%d\n",i,*pint++);
shmdt(addr1);
shmdt(addr2);
pause();
}21.semctl()功能:信號(hào)量控制操作.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semctl(semid,memnum,cmd,arg)int semid,semnum,cmd;
union semun {int val;
struct semid_ds *buf;
ushort *array;
}arg;
說(shuō)明:本系統(tǒng)調(diào)用提供了一個(gè)信號(hào)量控制操作,操作行為由cmd定義,這些命令是對(duì)由semid和semnum指定的信號(hào)量做操作的.每個(gè)命令都要求有相應(yīng)的權(quán)限級(jí)別:. GETVAL:返回semval的值,要求有讀權(quán)限.. SETVAL:設(shè)置semval的值到arg.val上.此命令成功執(zhí)行后,semadj的值對(duì)應(yīng)的所有進(jìn)程的信號(hào)量全部被清除,要求有修改權(quán)限.. GETPID:返回sempid的值,要求有讀權(quán)限.. GETNCNT:返回semncnt的值,要求有讀權(quán)限.. GETZCNT:返回semzcnt的值,要求有讀權(quán)限.以下命令在一組信號(hào)量中的各個(gè)semval上操作:. GETALL:返回每個(gè)semval的值,同時(shí)將各個(gè)值放入由arg.array指向的數(shù)組中.當(dāng)此命令成功執(zhí)行后,semadj的值對(duì)應(yīng)的所有進(jìn)程的信號(hào)量全部被清除,要求有修改權(quán)限.. SETALL:根據(jù)由arg.array指向的數(shù)組設(shè)置各個(gè)semval值.當(dāng)此命令成功執(zhí)行后,semadj的值對(duì)應(yīng)的所有進(jìn)程的信號(hào)量全部被清除,要求有修改權(quán)限.以下命令在任何情況下都是有效的:. IPC_STAT:將與semid相關(guān)的數(shù)據(jù)結(jié)構(gòu)的各個(gè)成員的值放入由arg.buf指向的結(jié)構(gòu)中.要求有讀權(quán)限.. IPC_SET:設(shè)置semid相關(guān)數(shù)據(jù)結(jié)構(gòu)的如下成員,設(shè)置數(shù)據(jù)從arg.buf指向的結(jié)構(gòu)中讀取:sem_perm.uidsem_perm.gidsem_perm.mode本命令只能由有效UID等于sem_perm.cuid或sem_perm.uid的進(jìn)程或有效UID有合適權(quán)限的進(jìn)程操作.. IPC_RMID:刪除由semid指定的信號(hào)量標(biāo)識(shí)符和相關(guān)的一組信號(hào)量及數(shù)據(jù)結(jié)構(gòu).本命令只能由有效UID等于sem_perm.cuid或sem_perm.uid的進(jìn)程或有效UID有合適權(quán)限的進(jìn)程操作.返回值:若調(diào)用成功,則根據(jù)cmd返回以下值:GETVAL:semval的值.GETPID:sempid的值.GETNCNT:semncnt的值.GETZCNT:semzcnt的值.其他:0.若調(diào)用失敗則返回-1.22.semget()功能:取得一組信號(hào)量.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semget(key,nsems,semflg)key_t key;
int nsems,semflg;
說(shuō)明:返回和key相關(guān)的信號(hào)量標(biāo)識(shí)符.若以下事實(shí)成立,則與信號(hào)量標(biāo)識(shí)符,與之相關(guān)的semid_ds數(shù)據(jù)結(jié)構(gòu)及一組nsems信號(hào)量將被創(chuàng)建:. key等于IPC_PRIVATE.. 系統(tǒng)內(nèi)還沒(méi)有與key相關(guān)的信號(hào)量,同時(shí)(semflg&IPC_CREAT)為真.創(chuàng)建時(shí)新的信號(hào)量相關(guān)的semid_ds數(shù)據(jù)結(jié)構(gòu)被初始化如下:. 在操作權(quán)限結(jié)構(gòu),sem_perm.cuid和sem_perm.uid設(shè)置等于調(diào)用進(jìn)程的有效UID.. 在操作權(quán)限結(jié)構(gòu),sem_perm.cgid和sem_perm.gid設(shè)置等于調(diào)用進(jìn)程的有效GID.. 訪問(wèn)權(quán)限比特位sem_perm.mode設(shè)置等于semflg的訪問(wèn)權(quán)限比特位.. sem_otime設(shè)置等于0,sem_ctime設(shè)置等于當(dāng)前系統(tǒng)時(shí)間.返回值:若調(diào)用成功,則返回一非0值,稱為信號(hào)量標(biāo)識(shí)符;否則返回-1.23.semop()功能:信號(hào)量操作.語(yǔ)法:#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semop(semid,sops,nsops)int semid;
struct sembuf *sops;
unsigned nsops;
說(shuō)明:本系統(tǒng)調(diào)用用于執(zhí)行用戶定義的在一組信號(hào)量上操作的行為集合.該組信號(hào)量與semid相關(guān).參數(shù)sops為一個(gè)用戶定義的信號(hào)量操作結(jié)構(gòu)數(shù)組指針.參數(shù)nsops為該數(shù)組的元素個(gè)數(shù).數(shù)組的每個(gè)元素結(jié)構(gòu)包括如下成員:sem_num; /* 信號(hào)量數(shù) */sem_op; /* 信號(hào)量操作 */sem_flg; /* 操作標(biāo)志 */
由本系統(tǒng)調(diào)用定義的每個(gè)信號(hào)量操作是針對(duì)由semid和sem_num指定的信號(hào)量的.變量sem_op指定三種信號(hào)量操作的一種:. 若sem_op為一負(fù)數(shù)并且調(diào)用進(jìn)程具有修改權(quán)限,則下列情況之一將會(huì)發(fā)生:* 若semval不小于sem_op的絕對(duì)值,則sem_op的絕對(duì)值被減去semval的值.若(semflg&SEM_UNDO)為真則sem_op的絕對(duì)值加上調(diào)用進(jìn)程指定的信號(hào)量的semadj值.* 若semval小于sem_op的絕對(duì)值同時(shí)(semflg&IPC_NOWAIT)為真,則本調(diào)用立即返回.* 若semval小于sem_op的絕對(duì)值同時(shí)(semflg&IPC_NOWAIT)為假,則本系統(tǒng)調(diào)用將增加指定信號(hào)量相關(guān)的semncnt值(加一),將調(diào)用進(jìn)程掛起直到下列條件之一被滿足:(1).semval值變成不小于sem_op的絕對(duì)值.當(dāng)這種情況發(fā)生時(shí),指定的信號(hào)量相關(guān)的semncnt減一,若(semflg&SEM_UNDO)為真則sem_op的絕對(duì)值加上調(diào)用進(jìn)程指定信號(hào)量的semadj值.(2).調(diào)用進(jìn)程等待的semid已被系統(tǒng)刪除.(3).調(diào)用進(jìn)程捕俘到信號(hào),此時(shí),指定信號(hào)量的semncnt值減一,調(diào)用進(jìn)程執(zhí)行中斷服務(wù)程序.. 若sem_op為一正值,同時(shí)調(diào)用進(jìn)程具有修改權(quán)限,sem_op的值加上semval的值,若(semflg&SEM_UNDO)為真,則sem_op減去調(diào)用進(jìn)程指定信號(hào)量的semadj值.. 若sem_op為0,同時(shí)調(diào)用進(jìn)程具有讀權(quán)限,下列情況之一將會(huì)發(fā)生:* 若semval為0,本系統(tǒng)調(diào)用立即返回.* 若semval不等于0且(semflg&IPC_NOWAIT)為真,本系統(tǒng)調(diào)用立即返回.* 若semval不等于0且(semflg&IPC_NOWAIT)為假,本系統(tǒng)調(diào)用將把指定信號(hào)量的semzcnt值加一,將調(diào)用進(jìn)程掛起直到下列情況之一發(fā)生:(1).semval值變?yōu)?時(shí),指定信號(hào)量的semzcnt值減一.(2).調(diào)用進(jìn)程等待的semid已被系統(tǒng)刪除.(3).調(diào)用進(jìn)程捕俘到信號(hào),此時(shí),指定信號(hào)量的semncnt值減一,調(diào)用進(jìn)程執(zhí)行中斷服務(wù)程序.返回值:調(diào)用成功則返回0,否則返回-1.例子:本例將包括上述信號(hào)量操作的所有系統(tǒng)調(diào)用:#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#define SEMKEY 75int semid;
unsigned int count;
/*在文件sys/sem.h中定義的sembuf結(jié)構(gòu)* struct sembuf {* unsigned short sem_num;
* short sem_op;
* short sem_flg;
* }*/struct sembuf psembuf,vsembuf; /*P和V操作*/
cleanup(){semctl(semid,2,IPC_RMID,0);
exit(0);
}main(argc,argv)int argc;
char *argv[];
{int i,first,second;
short initarray[2],outarray[2];
extern cleanup();
if (argc==1) {for (i=0;i<20;i++)signal(i,clearup);
semid=semget(SEMKEY,2,0777|IPC_CREAT);
initarray[0]=initarray[1]=1;
semctl(semid,2,SETALL,initarray);
semctl(semid,2,GETALL,outarray);
printf("sem init vals %d%d \n",outarray[0],outarray[1]);
pause(); /*睡眠到被一軟件中斷信號(hào)喚醒*/
}else if (argv[1][0]=='a') {first=0;
second=1;
}else {first=1;
second=0;
}semid=semget(SEMKEY,2,0777);
psembuf.sem_op=-1;
psembuf.sem_flg=SEM_UNDO;
vsembuf.sem_op=1;
vsembuf.sem_flg=SEM_UNDO;
for (count=0;;xcount++) {psembuf.sem_num=first;
semop(semid,&psembuf,1);
psembuf.sem_num=second;
semop(semid,&psembuf,1);
printf("proc %d count %d\n",getpid(),count);
vsembuf.sem_num=second;
semop(semid,&vsembuf,1);
vsembuf.sem_num=first;
semop(semid,&vsembuf,1);
}}24.sdenter()功能:共享數(shù)據(jù)段同步訪問(wèn),加鎖.語(yǔ)法:#include <sys/sd.h>int sdenter(addr,flags)char *addr;
int flags;
說(shuō)明:用于指示調(diào)用進(jìn)程即將可以訪問(wèn)共享數(shù)據(jù)段中的內(nèi)容.參數(shù)addr為將一個(gè)sdget()調(diào)用的有效返回碼.所執(zhí)行的動(dòng)作取決于flags的值:. SD_NOWAIT:若另一個(gè)進(jìn)程已對(duì)指定的段調(diào)用本系統(tǒng)調(diào)用且還沒(méi)有調(diào)用sdleave(),并且該段并非用SD_UNLOCK標(biāo)志創(chuàng)建,則調(diào)用進(jìn)程不是等待該段空閑而是立即返回錯(cuò)誤碼.. SD_WRITE:指示調(diào)用進(jìn)程希望向共享數(shù)據(jù)段寫數(shù)據(jù).此時(shí),另一個(gè)進(jìn)程用SD_RDONLY標(biāo)志聯(lián)接該共享數(shù)據(jù)段則不被允許.返回值:調(diào)用成功則返回0,否則返回-1.25.sdleave()功能:共享數(shù)據(jù)段同步訪問(wèn),解鎖.語(yǔ)法:#include <sys/sd.h>int sdleave(addr,flags)char *addr;
說(shuō)明:用于指示調(diào)用進(jìn)程已完成修改共享數(shù)據(jù)段中的內(nèi)容.返回值:調(diào)用成功則返回0,否則返回-1.26.sdget()功能:聯(lián)接共享數(shù)據(jù)段到調(diào)用進(jìn)程的數(shù)據(jù)空間中.語(yǔ)法:#include <sys/sd.h>char *sdget(path,flags,size.mode)char *path;
int flags;
long size;
int mode;
說(shuō)明:本系統(tǒng)調(diào)用將共享數(shù)據(jù)段聯(lián)接到調(diào)用進(jìn)程的數(shù)據(jù)段中,具體動(dòng)作由flags的值定義:. SD_RDONLY:聯(lián)接的段為只讀的.. SD_WRITE:聯(lián)接的段為可讀寫的.. SD_CREAT:若由path命名的段存在且不在使用中,本標(biāo)志的作用同早先創(chuàng)建一個(gè)段相同,否則,該段根據(jù)size和mode的值進(jìn)程創(chuàng)建.對(duì)段的讀寫訪問(wèn)權(quán)限的授予基于mode給的權(quán)限,功能與一般文件的相同.段被初始化為全0.. SD_UNLOCK:若用此標(biāo)志創(chuàng)建該段,則允許有多個(gè)進(jìn)程同時(shí)訪問(wèn)(在讀寫中)該段.返回值:若調(diào)用成功則返回聯(lián)接的段地址.否則返回-1.27.sdfree()功能:將共享數(shù)據(jù)段從調(diào)用進(jìn)程的數(shù)據(jù)空間中斷開(kāi)聯(lián)接.語(yǔ)法:#include <sys/sd.h>int sdfree(addr)char *addr;
說(shuō)明:本系統(tǒng)調(diào)用將共享數(shù)據(jù)段從調(diào)用進(jìn)程的數(shù)據(jù)段的指定地址中分離.若調(diào)用進(jìn)程已完成sdenter()的調(diào)用,還未調(diào)用sdleave()就調(diào)用本系統(tǒng)調(diào)用,則sdleave()被自動(dòng)調(diào)用,然后才做本調(diào)用的工作.返回值:若調(diào)用成功則返回聯(lián)接的段地址.否則返回-1.28.sdgetv()功能:同步共享數(shù)據(jù)訪問(wèn).語(yǔ)法:#include <sys/sd.h>int sdgetv(addr)char *addr;
說(shuō)明:用于同步協(xié)調(diào)正在使用共享數(shù)據(jù)段的進(jìn)程.返回值為共享數(shù)據(jù)段的版本號(hào).當(dāng)有進(jìn)程對(duì)該段做sdleave()操作時(shí),版本號(hào)會(huì)被修改.返回值:若調(diào)用成功,則返回指定共享數(shù)據(jù)段的版本號(hào),否則返回-1.29.sdwaitv()功能:同步共享數(shù)據(jù)訪問(wèn).語(yǔ)法:#include <sys/sd.h>int sdwaitv(addr,vnum)char *addr;
int vnum;
說(shuō)明:用于同步協(xié)調(diào)正在使用共享數(shù)據(jù)段的進(jìn)程.返回值為共享數(shù)據(jù)段的版本號(hào).調(diào)用進(jìn)程會(huì)睡眠直到指定段的版本號(hào)不再等于vnum;
返回值:若調(diào)用成功,則返回指定共享數(shù)據(jù)段的版本號(hào),否則返回-1.30.sbrk()功能:修改數(shù)據(jù)段空間分配.語(yǔ)法:char *sbrk(incr)int incr;
說(shuō)明:用于動(dòng)態(tài)修改調(diào)用進(jìn)程數(shù)據(jù)段的空間分配.進(jìn)程將重置進(jìn)程的分段值并分配一個(gè)合適大小的空間.分段值為數(shù)據(jù)段外第一次分配的地址.要分配的空間的增加量等于分段值的增加量.新分配的空間設(shè)置為0.若相同的內(nèi)存空間重新分配給同一個(gè)進(jìn)程,則空間的內(nèi)容不確定.返回值:若成功調(diào)用則返回值為0,否則返回-1.例子:本例將包括上述共享數(shù)據(jù)空間操作的所有系統(tǒng)調(diào)用:char * area1;
char buf[21];
int v;
/*取得或創(chuàng)建一個(gè)共享數(shù)據(jù)空間(系統(tǒng)特殊文件),名字為/tmp/area1,長(zhǎng)度為640,用戶訪問(wèn)權(quán)限為0777*/area1=sdget("/tmp/area1",SD_WRITE|SD_CREAT,640,0777);
if ((int)area1==-1) {printf("get share data segment area1 failed\n");
exit(1);
}/*取得共享數(shù)據(jù)段area1的版本號(hào)*/v=sdgetv(area1);
/*申請(qǐng)?jiān)L問(wèn)共享數(shù)據(jù)段area1,若已有進(jìn)程在訪問(wèn)該段則本進(jìn)程掛*起,否則進(jìn)入訪問(wèn)并將該數(shù)據(jù)段加寫鎖*/sdenter(area1,SD_WRITE);
/*對(duì)共享數(shù)據(jù)段訪問(wèn),寫10個(gè)a*/strcpy(area1,"aaaaaaaaaa");
/*申請(qǐng)解除訪問(wèn)權(quán)限,若已有進(jìn)程申請(qǐng)?jiān)L問(wèn)則激活該進(jìn)程*/sdleave(area1);
/*進(jìn)程處理過(guò)程*//*等待取共享數(shù)據(jù)段area1的版本號(hào)*/sdwaitv(area1,v);
/*重新申請(qǐng)?jiān)L問(wèn)共享數(shù)據(jù)段area1*/sdenter(area1,SD_WRITE);
/*讀取共享數(shù)據(jù)段中的數(shù)據(jù)*/memcpy(buf,area1,20);
/*申請(qǐng)解除訪問(wèn)權(quán)限,若已有進(jìn)程申請(qǐng)?jiān)L問(wèn)則激活該進(jìn)程*/sdleave(area1);
printf("the data now in area1 is [%s]\n",buf);
31.getenv()功能:取得指定環(huán)境變量值.語(yǔ)法:#include <unistd.h>#include <stdlib.h.char *getenv(name)char *name;
說(shuō)明:本系統(tǒng)調(diào)用檢查環(huán)境字符串(格式如name=value),并在找到有指定名字的環(huán)境值后,返回指向value字符串的指針.否則返回空指針.返回值:如前述.例子:char * value;
value=getenv("HOME");
printf("HOME = [%s]\n",value);
/*將打印出HOME環(huán)境變量的值*/32.putenv()功能:修改或增加環(huán)境值.語(yǔ)法:#include <stdlib.h>int putenv(string)char *string;
說(shuō)明:參數(shù)string指向一個(gè)字符串,格式如下:name=value本系統(tǒng)調(diào)用將環(huán)境變量name等于值value,修改或增加一個(gè)環(huán)境變量,字符串string成為環(huán)境的一部分.返回值:若putenv()不能取得合適的內(nèi)存空間則返回非0值,否則返回0.例子:/*父進(jìn)程處理*/putenv("HOME=/home/abcdef");
putenv("PATH=/bin");
if (fork()>0)exit(0); /*父進(jìn)程退出運(yùn)行*/
/*子進(jìn)程處理*/setpgrp();
/*父進(jìn)程設(shè)置的環(huán)境變量已傳到子進(jìn)程*/char * value1;
value1=getenv("HOME");
value2=getenv("PATH");
printf("HOME=[%s],PATH=[%s]\n",value1,value2);
/*將打印出"HOME=/home/abcdef"和"PATH=/bin"*/
三.多進(jìn)程編程技巧1.主要程序結(jié)構(gòu)(1)事件主控方式若是應(yīng)用程序?qū)儆谑聞?wù)處理方式,則在主函數(shù)中設(shè)計(jì)為監(jiān)控事件發(fā)生,當(dāng)事件發(fā)生時(shí),可以生成一個(gè)新的進(jìn)程來(lái)處理該事務(wù),事務(wù)處理完成后就可以讓子進(jìn)程退出系統(tǒng).這種處理方式一般不要消息傳遞.(2)信息協(xié)調(diào)方式若是應(yīng)用程序需要由多個(gè)進(jìn)程協(xié)調(diào)處理完成,則可以生成這些進(jìn)程,通過(guò)消息在進(jìn)程間的傳遞,使各個(gè)進(jìn)程能相互協(xié)調(diào),共同完成事務(wù).這種處理方式一般是用fork()生成幾個(gè)進(jìn)程后,用exec()調(diào)用其它程序文件,使得不同的程序同時(shí)在系統(tǒng)內(nèi)運(yùn)行.然后通過(guò)IPC機(jī)制傳送消息,使各個(gè)程序能協(xié)調(diào)運(yùn)行.2.選擇主體分叉點(diǎn)(1)事件初始產(chǎn)生對(duì)應(yīng)于事件主控方式的程序結(jié)構(gòu).關(guān)鍵點(diǎn)在于以何種方式選擇事件的初始發(fā)生點(diǎn),如網(wǎng)絡(luò)程序給出的建鏈信息.主控程序在收到該消息后就認(rèn)為是一個(gè)事件開(kāi)始,則可以產(chǎn)生一個(gè)子進(jìn)程處理后面的事務(wù):接收交易信息,事務(wù)處理,發(fā)送返回交易信息,關(guān)閉鏈接等,完成后將子進(jìn)程退出系統(tǒng).(2)主程序自主產(chǎn)生對(duì)應(yīng)于信息協(xié)調(diào)方式的程序結(jié)構(gòu).主控程序只負(fù)責(zé)生成幾個(gè)子進(jìn)程,各個(gè)子進(jìn)程分別調(diào)用exec()將不同的執(zhí)行文件調(diào)入內(nèi)存運(yùn)行,主控程序在生成所有的子進(jìn)程后即可退出系統(tǒng),將子進(jìn)程留在內(nèi)存中運(yùn)行.3.進(jìn)程間關(guān)系處理(1)父子進(jìn)程關(guān)系. 進(jìn)程組處理進(jìn)程組的概念是這樣的,當(dāng)系統(tǒng)啟動(dòng)時(shí),第一個(gè)進(jìn)程是init,其進(jìn)程組號(hào)等于進(jìn)程號(hào),由它產(chǎn)生的所有子進(jìn)程的進(jìn)程組號(hào)也相同,子進(jìn)程的子進(jìn)程也繼承該進(jìn)程組號(hào),這樣,由init所生成的所有子進(jìn)程都屬于同一個(gè)進(jìn)程組.但是,同一個(gè)進(jìn)程組的父子進(jìn)程可能在信號(hào)上有相互通訊,若父進(jìn)程先于子進(jìn)程退出系統(tǒng),則子進(jìn)程會(huì)成為一個(gè)孤兒進(jìn)程,可能變成僵死進(jìn)程.從而使該子進(jìn)程在其不"愿意"的情況下退出運(yùn)行.為解決這個(gè)問(wèn)題,子進(jìn)程可以自己組成一個(gè)新的進(jìn)程組,即調(diào)用setpgrp()與原進(jìn)程組脫離關(guān)系,產(chǎn)生一個(gè)新的進(jìn)程組,進(jìn)程組號(hào)與它的進(jìn)程號(hào)相同.這樣,父進(jìn)程退出運(yùn)行后就不會(huì)影響子進(jìn)程的當(dāng)前運(yùn)行.. 子進(jìn)程信號(hào)處理但是,單做上述處理還不能解決另一個(gè)困難,即子進(jìn)程在退出運(yùn)行時(shí),找不到其父進(jìn)程(父進(jìn)程已退出,子進(jìn)程的父進(jìn)程號(hào)改為1).發(fā)送子進(jìn)程退出信號(hào)后沒(méi)有父進(jìn)程做出響應(yīng)處理,該子進(jìn)程就不可能完全退出運(yùn)行,可能進(jìn)入僵死狀態(tài).所以父進(jìn)程在產(chǎn)生子進(jìn)程前最好屏蔽子進(jìn)程返回信號(hào)的處理,生成子進(jìn)程,在父進(jìn)程退出運(yùn)行后,子進(jìn)程返回則其進(jìn)程返回信號(hào)的處理會(huì)由系統(tǒng)給出缺省處理,子進(jìn)程就可以正常退出.(2)兄弟進(jìn)程關(guān)系. 交換進(jìn)程號(hào)對(duì)于信息協(xié)調(diào)方式的程序來(lái)說(shuō),各兄弟進(jìn)程間十分需要相互了解進(jìn)程號(hào),以便于信號(hào)處理機(jī)制.比較合理的方法是父進(jìn)程生成一個(gè)共享內(nèi)存的空間,每個(gè)子進(jìn)程都在啟動(dòng)時(shí)在共享內(nèi)存中設(shè)置自己的進(jìn)程號(hào).這樣,當(dāng)一個(gè)子進(jìn)程要向另一個(gè)子進(jìn)程發(fā)送信號(hào)或是因?yàn)槠渌蛐枰懒硪粋€(gè)子進(jìn)程號(hào)時(shí),就可以在共享內(nèi)存中訪問(wèn)得到所需要的進(jìn)程號(hào).4.進(jìn)程間通訊處理(1)共享內(nèi)存需要鎖機(jī)制由于共享內(nèi)存在設(shè)計(jì)時(shí)沒(méi)有處理鎖機(jī)制,故當(dāng)有多個(gè)進(jìn)程在訪問(wèn)共享內(nèi)存時(shí)就會(huì)產(chǎn)生問(wèn)題.如:一個(gè)進(jìn)程修改一個(gè)共享內(nèi)存單元,另一個(gè)進(jìn)程在讀該共享內(nèi)存單元時(shí)可能有第三個(gè)進(jìn)程立即修改該單元,從而會(huì)影響程序的正確性.同時(shí)還有分時(shí)系統(tǒng)對(duì)各進(jìn)程是分時(shí)間片處理的,可能會(huì)引起不同的正確性問(wèn)題.按操作系統(tǒng)的運(yùn)作方式,則有讀鎖和寫鎖來(lái)保證數(shù)據(jù)的一致性.所以沒(méi)有鎖機(jī)制的共享內(nèi)存,必須和信號(hào)量一起使用,才能保證共享內(nèi)存的正確操作.(2)消息隊(duì)列需要關(guān)鍵值消息隊(duì)列的操作在進(jìn)程取得消息隊(duì)列的訪問(wèn)權(quán)限后就必須通過(guò)關(guān)鍵值來(lái)讀消息隊(duì)列中的相同關(guān)鍵值的消息,寫消息時(shí)帶入消息關(guān)鍵值.這樣可以通過(guò)不同的關(guān)鍵值區(qū)分不同的交易,使得在同一個(gè)消息隊(duì)列可以供多種消息同時(shí)使用而不沖突.若讀消息隊(duì)列使用關(guān)鍵值0則讀取消息隊(duì)列中第一個(gè)消息,不論其關(guān)鍵值如何.(3)信號(hào)需要信號(hào)處理函數(shù)設(shè)置和再設(shè)置在用戶進(jìn)程需要對(duì)某個(gè)中斷做自己定義的處理時(shí),可以自己定義中斷處理函數(shù),并設(shè)置中斷處理函數(shù)與該中斷相關(guān)聯(lián).這樣,用戶進(jìn)程在收到該中斷后,即調(diào)用用戶定義的函數(shù),處理完成后用戶進(jìn)程從被中斷處繼續(xù)運(yùn)行(若用戶定義的中斷函數(shù)沒(méi)有長(zhǎng)跳函數(shù)或退出運(yùn)行等會(huì)改變運(yùn)行指令地址的系統(tǒng)調(diào)用).在中斷信號(hào)被處理后,該中斷的處理函數(shù)會(huì)恢復(fù)成上次缺省處理函數(shù)而不是保持用戶定義函數(shù),故在用戶定義的中斷處理函數(shù)中一般都再定義該中斷和函數(shù)自己的關(guān)聯(lián).(4)IPC的權(quán)限設(shè)置在消息隊(duì)列,共享內(nèi)存和信號(hào)量的訪問(wèn)時(shí)有用戶訪問(wèn)權(quán)限設(shè)置,類同于文件的訪問(wèn)權(quán)限的設(shè)置如(777表示rwxrwxrwx),用命令ipcs即可看到在系統(tǒng)中生成的消息隊(duì)列,共享內(nèi)存和信號(hào)量的訪問(wèn)權(quán)限.其意義也類似于文件訪問(wèn)權(quán)限.只是執(zhí)行位無(wú)效.在有名管道和文件方式共享內(nèi)存中以系統(tǒng)文件的方式定義了用戶的訪問(wèn)權(quán)限.用命令ls -l可以看到它們以系統(tǒng)文件方式存在并具有訪問(wèn)權(quán)限值,并可以看到有名管道的文件類型為p,文件方式共享內(nèi)存的文件類型為s.(5)信號(hào)中斷對(duì)系統(tǒng)調(diào)用一級(jí)有效系統(tǒng)在設(shè)計(jì)系統(tǒng)調(diào)用時(shí)就考慮了中斷處理問(wèn)題.當(dāng)進(jìn)程運(yùn)行到一個(gè)系統(tǒng)調(diào)用時(shí)發(fā)生了中斷,則進(jìn)程進(jìn)入該中斷處理,處理完成后,進(jìn)程會(huì)跳過(guò)該系統(tǒng)調(diào)用而進(jìn)入下一條程序指令.應(yīng)該注意的是中斷發(fā)生在系統(tǒng)調(diào)用一級(jí)而不是子程序或函數(shù)一級(jí).比如一個(gè)程序在一個(gè)子程序被調(diào)用前設(shè)置了超時(shí)中斷,并在子程序中收到超時(shí)中斷,系統(tǒng)在處理完超時(shí)中斷后接著處理該子程序被中斷的系統(tǒng)調(diào)用之后的指令,而不是從調(diào)用該子程序名指令的后一條指令繼續(xù)處理.(6)各種IPC方式的特點(diǎn). 消息隊(duì)列:通過(guò)消息隊(duì)列key值定義和生成消息隊(duì)列.任何進(jìn)程只要有訪問(wèn)權(quán)限并知道key即可訪問(wèn)消息隊(duì)列.消息隊(duì)列為內(nèi)存塊方式數(shù)據(jù)段.消息隊(duì)列中的消息元素長(zhǎng)度可為系統(tǒng)參數(shù)限制內(nèi)的任何長(zhǎng)度.消息元素由消息類型分類,其訪問(wèn)方式為按類型訪問(wèn).在一次讀寫操作前都必須取得消息隊(duì)列標(biāo)識(shí)符,即訪問(wèn)權(quán).訪問(wèn)后即脫離訪問(wèn)關(guān)系.消息隊(duì)列中的某條消息被讀后即從隊(duì)列中刪除.消息隊(duì)列的訪問(wèn)具備鎖機(jī)制處理,即一個(gè)進(jìn)程在訪問(wèn)時(shí)另一個(gè)進(jìn)程不能訪問(wèn).操作時(shí)要注意系統(tǒng)資源和效率.在權(quán)限允許時(shí),消息隊(duì)列的信息傳遞是雙向的.. 共享內(nèi)存通過(guò)共享內(nèi)存key值定義和生成共享內(nèi)存.任何進(jìn)程只要有訪問(wèn)權(quán)限并知道key即可訪問(wèn)共享內(nèi)存.共享內(nèi)存為內(nèi)存塊方式的數(shù)據(jù)段.共享內(nèi)存中的數(shù)據(jù)長(zhǎng)度可為系統(tǒng)參數(shù)限制內(nèi)的任何長(zhǎng)度.共享內(nèi)存的訪問(wèn)同數(shù)組的訪問(wèn)方式相同.在取得共享內(nèi)存標(biāo)識(shí)符將共享內(nèi)存與進(jìn)程數(shù)據(jù)段聯(lián)接后即可開(kāi)始對(duì)之進(jìn)行讀寫操作,在所有操作完成之后再做共享內(nèi)存和進(jìn)程數(shù)據(jù)段脫離操作,才完成全部共享內(nèi)存訪問(wèn)過(guò)程.共享內(nèi)存中的數(shù)據(jù)不會(huì)因數(shù)據(jù)被進(jìn)程讀取后消失.共享內(nèi)存的訪問(wèn)不具備鎖機(jī)制處理,即多個(gè)進(jìn)程可能同時(shí)訪問(wèn)同一個(gè)共享內(nèi)存的同一個(gè)數(shù)據(jù)單元.共享內(nèi)存的使用最好和信號(hào)量一起操作,以具備鎖機(jī)制,保證數(shù)據(jù)的一致.在權(quán)限允許時(shí),共享內(nèi)存的信息傳遞是雙向的.. 信號(hào)量用于生成鎖機(jī)制,避免發(fā)生數(shù)據(jù)不一致.沒(méi)有其他的數(shù)據(jù)信息.不需要有父子關(guān)系或兄弟關(guān)系.. 信號(hào)信號(hào)由系統(tǒng)進(jìn)行定義.信號(hào)的發(fā)送只要有權(quán)限即可進(jìn)行.信號(hào)是一個(gè)事件發(fā)生的信息標(biāo)志,不帶有其它信息.信號(hào)不具備數(shù)據(jù)塊.信號(hào)的處理可由用戶自己定義.信號(hào)可能由用戶進(jìn)程,操作系統(tǒng)(軟件或硬件原因)等發(fā)出.有一些信號(hào)是不可被屏蔽的.信號(hào)中斷的是系統(tǒng)調(diào)用級(jí)的函數(shù).信號(hào)的信息傳遞是單向的.. 管道做為系統(tǒng)的特殊設(shè)備文件,可以是內(nèi)存方式的,也可以是外存方式的.管道的傳輸一般是單向的,即一個(gè)管道一向,若兩個(gè)進(jìn)程要做雙向傳輸則需要2個(gè)管道.管道生成時(shí)即有兩端,一端為讀,一端為寫,兩個(gè)進(jìn)程要協(xié)調(diào)好,一個(gè)進(jìn)程從讀方讀,另一個(gè)進(jìn)程向?qū)懛綄?管道的讀寫使用流設(shè)備的讀寫函數(shù),即:read(),write.管道的傳輸方式為FIFO,流方式的.不象消息隊(duì)列可以按類型讀取.* 有名管道一般為系統(tǒng)特殊文件方式,使用的進(jìn)程之間不一定要有父子關(guān)系或兄弟關(guān)系.* 無(wú)名管道一般為內(nèi)存方式,使用的進(jìn)程之間一定要有父子關(guān)系或兄弟關(guān)系.. 文件文件是最簡(jiǎn)單的進(jìn)程間通訊方式,使用外部存貯器為中介.操作麻煩,定位困難.保密程度低.容易出現(xiàn)數(shù)據(jù)不一致問(wèn)題.占用硬盤空間.只要有權(quán)限并知道文件名,任何進(jìn)程都可對(duì)之操作.* 特殊處理為避免出現(xiàn)保密問(wèn)題,在打開(kāi)文件,取得文件描述符后,調(diào)用unlink()將硬盤上的文件路徑名刪除,則硬盤上就沒(méi)有文件拷貝了.但在進(jìn)程中該文件描述符是打開(kāi)的,由該進(jìn)程生成的子進(jìn)程中該文件描述符也是打開(kāi)的,就可以利用系統(tǒng)提供的文件緩沖區(qū)做進(jìn)程間通訊,代價(jià)是進(jìn)程間必須有父子關(guān)系或兄弟關(guān)系.. 環(huán)境變量信息的傳送一般是單向的,即由父進(jìn)程向子進(jìn)程傳送.保密性較好.雙方必須約定環(huán)境變量名.只占用本進(jìn)程和子進(jìn)程的環(huán)境變量區(qū).. 共享數(shù)據(jù)段操作比較復(fù)雜.占用硬盤空間,生成系統(tǒng)特殊文件.其他性質(zhì)與共享內(nèi)存相類似.. 流文件描述符的操作方式.進(jìn)程間不一定要有父子關(guān)系或兄弟關(guān)系.雙向傳送信息.進(jìn)程各自生成socket,用bind()聯(lián)接.其他性質(zhì)與管道相類似.流編程為TCP/IP網(wǎng)絡(luò)編程范圍,在本文中暫不闡述.. 傳遞參數(shù)信息的傳送一般是單向的, 即由父進(jìn)程向子進(jìn)程傳送.保密性較差,用進(jìn)程列表即可顯示出來(lái).雙方必須約定參數(shù)位置.只占用子進(jìn)程的參數(shù)區(qū).
--
[m[1;32m※ 來(lái)源:.飲水思源 bbs.sjtu.edu.cn.[FROM: 202.112.26.40][m
>From hawdog.bbs@bbs.sjtu.edu.cn Fri Nov 29 11:33:33 1996
?
轉(zhuǎn)載于:https://www.cnblogs.com/unixshell/p/3338003.html
總結(jié)
- 上一篇: std::remove
- 下一篇: 使用DPM 2010备份还原Exchan