




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、嵌入式Linux進(jìn)程和線程編程課程目標(biāo)v進(jìn)程相關(guān)的基本概念vLinux進(jìn)程的創(chuàng)建vLinux進(jìn)程的管理和守護(hù)進(jìn)程vLinux進(jìn)程間通信的方式vLinux中線程創(chuàng)建和退出vLinux中線程間的同步和互斥 本章內(nèi)容v6.1 Linux進(jìn)程概述 v6.2 Linux進(jìn)程控制相關(guān)API v6.3 ARM Linux進(jìn)程間通信 v6.4 ARM Linux線程相關(guān)API v6.5 Linux守護(hù)進(jìn)程 v本章小結(jié)6.1 Linux進(jìn)程概述v6.1.1 進(jìn)程描述符及任務(wù)結(jié)構(gòu) v6.1.2 進(jìn)程的調(diào)度 v6.1.3 Linux中的線程6.1.1 進(jìn)程描述符及任務(wù)結(jié)構(gòu)v進(jìn)程概念 進(jìn)程的概念首先在20世紀(jì)60年代
2、初期由MIT的Multics系統(tǒng)和IBM的TSS/360系統(tǒng)中引入的。 v(1)進(jìn)程是一個(gè)獨(dú)立的可調(diào)度的活動(dòng)(E.Cohen,D.Jofferson)。v(2)進(jìn)程是一個(gè)抽象實(shí)體,當(dāng)它執(zhí)行某個(gè)任務(wù)時(shí),將要分配和釋放各種資源(P.Denning)。v(3)進(jìn)程是可以并行執(zhí)行的計(jì)算部分(S.E.Madnick,J.T.Donovan)。進(jìn)程和程序有本質(zhì)的區(qū)別:程序是靜態(tài)的,它是一些保存在磁盤上的指令的有序集合,沒有任何執(zhí)行的概念;而進(jìn)程是一個(gè)動(dòng)態(tài)的概念,它是程序執(zhí)行的過程,包括了動(dòng)態(tài)創(chuàng)建、調(diào)度和消亡的整個(gè)過程,它是程序執(zhí)行和資源管理的最小單位。 6.1.1 進(jìn)程描述符及任務(wù)結(jié)構(gòu)vLinux中進(jìn)程描
3、述符進(jìn)程不但包括程序的指令和數(shù)據(jù),而且包括程序計(jì)數(shù)器和CPU的所有寄存器以及存儲(chǔ)臨時(shí)數(shù)據(jù)的進(jìn)程堆棧。內(nèi)核把進(jìn)程存放在任務(wù)隊(duì)列(task list)的雙向循環(huán)鏈表中,其中鏈表的每一項(xiàng)都是類型為task_struct,稱為進(jìn)程描述符的結(jié)構(gòu),該結(jié)構(gòu)定義在中 。6.1.1 進(jìn)程描述符及任務(wù)結(jié)構(gòu)vLinux中進(jìn)程描述符Linux通過slab分配器分配task_struct結(jié)構(gòu),它實(shí)際上是一個(gè)棧,其棧頂(向上增長的棧)或棧底(向下增長的棧)中有一個(gè)thread info結(jié)構(gòu),其中的task指針指向task_struct。下面詳細(xì)講解task_struct結(jié)構(gòu)中最為重要的兩個(gè)域:state和pid。6.1.
4、1 進(jìn)程描述符及任務(wù)結(jié)構(gòu)vLinux中進(jìn)程描述符v(1)進(jìn)程狀態(tài)運(yùn)行(TASK_RUNNING)可中斷(TASK_INTERUPTIBLE)不可中斷(TASK_UNINTERUPTIBLE)僵死(TASK_ZOMBIE)停止(TASK_STOPPED) 現(xiàn)在的任務(wù)調(diào)用 fork () 函數(shù)并且創(chuàng)建 一個(gè)新進(jìn)程 TASK _ RUNNING ( 準(zhǔn)備就緒但還未 運(yùn)行 ) TASK _ RUNNING ( 正在運(yùn)行 ) TASK _ INTERRUPTIBLE 或 TASK _ UNINTERRUPTIBLE TASK _ ZOMBIE ( 任務(wù)被終止 ) 調(diào)度程序?qū)?任務(wù)投入運(yùn)行 任務(wù)被更高 的
5、優(yōu)先級(jí)搶占 為等待特定事件 任務(wù)睡眠 等待的特定事件 發(fā)生后任務(wù)被喚醒 6.1.1 進(jìn)程描述符及任務(wù)結(jié)構(gòu)vLinux中進(jìn)程描述符v(2)任務(wù)標(biāo)識(shí)Linux內(nèi)核通過惟一的進(jìn)程標(biāo)識(shí)值PID來標(biāo)識(shí)每個(gè)進(jìn)程。PID是一個(gè)非負(fù)數(shù),它實(shí)際上是一個(gè)短整型數(shù)據(jù),也就是說它最大值為32767。讀者可以查看/proc/sys/kernel/pid_max來確定該系統(tǒng)的進(jìn)程數(shù)上限。一般來說,32767對于很多桌面系統(tǒng)已經(jīng)足夠,但是對于大型服務(wù)器,就必須修改這個(gè)上限。6.1.1 進(jìn)程描述符及任務(wù)結(jié)構(gòu)v進(jìn)程的創(chuàng)建、執(zhí)行和終止 v(1)進(jìn)程的創(chuàng)建和執(zhí)行許多操作系統(tǒng)都提供的是產(chǎn)生進(jìn)程的機(jī)制,也就是首先在新的地址空間里創(chuàng)建進(jìn)
6、程、讀入可執(zhí)行文件,最后再開始執(zhí)行。 首先,fork()通過拷貝當(dāng)前進(jìn)程的內(nèi)容創(chuàng)建一個(gè)子進(jìn)程,子進(jìn)程與父進(jìn)程的區(qū)別僅僅在于不同的PID、PPID和其他一些資源。exec函數(shù)負(fù)責(zé)讀取可執(zhí)行文件并將其載入地址空間開始運(yùn)行。6.1.1 進(jìn)程描述符及任務(wù)結(jié)構(gòu)v進(jìn)程的創(chuàng)建、執(zhí)行和終止 v(2)進(jìn)程的終止進(jìn)程終結(jié)也需要做很多繁瑣的收尾工作,系統(tǒng)必須保證進(jìn)程所占用的資源回收,并通知父進(jìn)程。Linux首先把終止的進(jìn)程設(shè)置為僵死狀態(tài),這個(gè)時(shí)候,進(jìn)程無法投入運(yùn)行了。它的存在只為父進(jìn)程提供信息,申請死亡。父進(jìn)程得到信息后,開始調(diào)用wait (),子進(jìn)程占用的資源被全部釋放。6.1.2 進(jìn)程的調(diào)度vLinux中進(jìn)程調(diào)
7、度概述 vLinux中進(jìn)程調(diào)度算法 Linux中進(jìn)程調(diào)度概述v進(jìn)程調(diào)度是指確定CPU當(dāng)前執(zhí)行哪個(gè)進(jìn)程。Linux進(jìn)程調(diào)度策略是以優(yōu)先級(jí)調(diào)度為基礎(chǔ)的,即優(yōu)先運(yùn)行優(yōu)先級(jí)最高的進(jìn)程。根據(jù)優(yōu)先級(jí)的范圍,可以把進(jìn)程分為實(shí)時(shí)進(jìn)程(這里的實(shí)時(shí)是軟實(shí)時(shí))和普通進(jìn)程。實(shí)時(shí)進(jìn)程優(yōu)先級(jí)高于普通進(jìn)程,并由特定的調(diào)度策略來保證它們的(軟)實(shí)時(shí)性。v內(nèi)核中的默認(rèn)配置是:進(jìn)程優(yōu)先級(jí)在0139,其中實(shí)時(shí)進(jìn)程占用099,一般進(jìn)程占用100139。v在調(diào)度時(shí),系統(tǒng)總是首先選取具有最高優(yōu)先級(jí)的并且擁有活躍進(jìn)程的進(jìn)程組,然后進(jìn)行相同優(yōu)先級(jí)下的進(jìn)程調(diào)度。 Linux中進(jìn)程調(diào)度算法vLinux 2.6內(nèi)核中實(shí)現(xiàn)了一個(gè)O(1)的調(diào)度算法,
8、也就是說每一次調(diào)度所需要的時(shí)間與該CPU內(nèi)的總進(jìn)程數(shù)無關(guān) 。vLinux中每個(gè)運(yùn)行隊(duì)列都有兩個(gè)優(yōu)先級(jí)數(shù)組,一個(gè)活躍的和一個(gè)過期的。優(yōu)先級(jí)數(shù)組在kernel/sched.c中被定義,它是prio_array類型的結(jié)構(gòu)體。struct prio_array unsigned int nr_active; /* 當(dāng)前活躍的進(jìn)程總數(shù) */ unsigned long bitmapBITMAP_SIZE;/* 活躍進(jìn)程的位圖 */ struct list_head queueMAX_PRIO; /* 各個(gè)優(yōu)先級(jí)隊(duì)列的頭指針組成的數(shù)組*/;6.1.3 Linux中的線程v線程機(jī)制是現(xiàn)代編程技術(shù)中常用的一種
9、抽象,該機(jī)制提供了在同一程序內(nèi)共享內(nèi)存地址空間運(yùn)行的一組線程。這些線程可以共享打開的文件和其他資源等。vLinux中實(shí)現(xiàn)線程的機(jī)制非常獨(dú)特。從內(nèi)核的角度來說,它并沒有線程這個(gè)概念。Linux把線程都當(dāng)作進(jìn)程來實(shí)現(xiàn),僅僅將其視為使用某些共享資源的進(jìn)程。每個(gè)線程都用有惟一隸屬于自己的task_struct,所以在內(nèi)核中,它看起來就像一個(gè)普通的進(jìn)程 。6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建fork(1)fork函數(shù)說明執(zhí)行一次返回兩個(gè)值,父進(jìn)程的返回值是子進(jìn)程的進(jìn)程號(hào),而子進(jìn)程則返回0 。 (2)fork函數(shù)語法fork函數(shù)的語法格式如下所示。頭文件#include / 提供類型pid_
10、t的定義#include 函數(shù)原型pid_t fork(void);函數(shù)返回值0:子進(jìn)程子進(jìn)程ID(大于0的整數(shù)):父進(jìn)程-1:出錯(cuò)6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建v(3)fork函數(shù)調(diào)用實(shí)例v/*調(diào)用fork函數(shù),其返回值賦給result*/vint result = fork();v/*通過result的值來判斷fork函數(shù)的返回情況,首先進(jìn)行出錯(cuò)處理*/vif(result = -1)v perror(fork);v exit(-1);vv/*返回值為0代表子進(jìn)程*/vWhile(1) if(result = 0)v printf(“child process”);sl
11、eep(1);/*子進(jìn)程相關(guān)語句*/vv/*返回值大于0代表父進(jìn)程*/velsev printf(“parent process”);sleep(1);/*父進(jìn)程相關(guān)語句*/vv6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建exec函數(shù)族(1)exec函數(shù)族說明vfork函數(shù)是用于創(chuàng)建一個(gè)子進(jìn)程,該子進(jìn)程幾乎拷貝了父進(jìn)程的全部內(nèi)容。 vexec函數(shù)族就提供了一個(gè)在進(jìn)程中啟動(dòng)另一個(gè)程序執(zhí)行的方法。它可以根據(jù)指定的路徑和文件名找到可執(zhí)行文件,并用它來取代原調(diào)用進(jìn)程的數(shù)據(jù)段、代碼段和堆棧段,在執(zhí)行完之后,原調(diào)用進(jìn)程的內(nèi)容除了進(jìn)程號(hào)外,其他全部被新的內(nèi)容替換了。另外,這里的可執(zhí)行文件既可以是二進(jìn)制
12、文件,也可以是Linux下任何可執(zhí)行的腳本文件。6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建exec函數(shù)族v(2)exec函數(shù)族語法v實(shí)際上,在Linux中并沒有exec()函數(shù),而是以exec開頭的函數(shù)族,它們之間語法有細(xì)微差別。vexec函數(shù)族語法格式如下所示。v 頭文件#include v 函數(shù)原型int execl(const char *path, const char *arg, .);int execv(const char *path, char *const argv);int execle(const char *path, const char *arg, ., c
13、har *const envp);int execve(const char *path, char *const argv, char *const envp);int execlp(const char *file, const char *arg, .);int execvp(const char *file, char *const argv);v函數(shù)返回值出錯(cuò)1:-16.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建exec函數(shù)族v(2)exec函數(shù)族語法6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建exec函數(shù)族v(3)exec函數(shù)組調(diào)用實(shí)例使用execlp函數(shù),采用逐個(gè)列舉方
14、式,并且使用系統(tǒng)默認(rèn)的環(huán)境變量。使用execl函數(shù)時(shí)需要給出完整的文件路徑來查找對應(yīng)的可執(zhí)行文件。if(fork()=0)/*調(diào)用execlp函數(shù),這里相當(dāng)于調(diào)用了“l(fā)s -l”命令*/ if(execlp(ls,ls,-l,NULL)0) perror(execlp error!);/*調(diào)用execl函數(shù),注意這里要給出ls程序所在的完整路徑*/if(execl(/bin/ls,ls,-l,NULL)0) perror(execl error!);6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建exec函數(shù)族v(3)exec函數(shù)組調(diào)用實(shí)例使用execle時(shí)可以將環(huán)境變量添加到新建的子進(jìn)程中
15、去 使用execve函數(shù)時(shí),通過構(gòu)造指針數(shù)組的方式來傳遞參數(shù),注意參數(shù)列表一定要以NULL作為結(jié)尾標(biāo)識(shí)符。/*命令參數(shù)列表,必須以NULL結(jié)尾*/char *envp=PATH=/tmp,USER=sunq,NULL;/*調(diào)用execle函數(shù),注意這里也要指出env的完整路徑*/if(execle(/bin/env,env,NULL,envp)0) perror(execle error!);/*命令參數(shù)列表,必須以NULL結(jié)尾*/char *arg=env,NULL;char *envp=PATH=/tmp,USER=sunq,NULL;if(execve(/bin/env,arg,envp
16、)0) perror(execve error!);寫一個(gè)程序?qū)崿F(xiàn)循環(huán)10次 輸出“child process replaced”,并睡眠2秒,然后在示例代碼中使用exec調(diào)用該程序,替換子進(jìn)程6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建exit和_exit(1)exit和_exit函數(shù)說明exit和_exit函數(shù)都是用來終止進(jìn)程的。當(dāng)程序執(zhí)行到exit或_exit時(shí),進(jìn)程會(huì)無條件地停止剩下的所有操作,清除包括PCB在內(nèi)的各種數(shù)據(jù)結(jié)構(gòu),并終止本進(jìn)程的運(yùn)行。exit()函數(shù)與_exit()函數(shù)的區(qū)別就在于exit()函數(shù)在調(diào)用exit系統(tǒng)調(diào)用之前要檢查進(jìn)程中文件的打開情況,把文件緩沖區(qū)中的
17、內(nèi)容寫回文件。如果用_exit()函數(shù)直接將進(jìn)程關(guān)閉,緩沖區(qū)中的數(shù)據(jù)就會(huì)丟失。因此,若想保證數(shù)據(jù)的完整性,就要使用exit()函數(shù)。6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建 5.26exit和_exit(2)exit和_exit函數(shù)語法exit和_exit函數(shù)的語法如下所示。頭文件vexit:#include v_exit:#include 函數(shù)原型vvoid exit/_exit(int status); /*利用該參數(shù)傳遞進(jìn)程結(jié)束時(shí)的狀態(tài)。一般來說,0表示正常結(jié)束;其他的數(shù)值表示出現(xiàn)了錯(cuò)誤,進(jìn)程非正常結(jié)束*/(3)exit和_exit使用實(shí)例exit和_exit函數(shù)的調(diào)用很簡單,
18、輸入狀態(tài)參數(shù)即可,如下所示:vexit(0);v_exit(-1);6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建wait和waitpid (1)wait和waitpid函數(shù)說明wait函數(shù)可以使父進(jìn)程(也就是調(diào)用wait的進(jìn)程)阻塞,直到任意一個(gè)子進(jìn)程結(jié)束或者父進(jìn)程接到了一個(gè)指定的信號(hào)為止。如果該父進(jìn)程沒有子進(jìn)程或者他的子進(jìn)程已經(jīng)結(jié)束,則wait函數(shù)會(huì)立即返回。waitpid的作用和wait一樣,但它并不一定要等待第一個(gè)終止的子進(jìn)程。它還有若干選項(xiàng),如可提供一個(gè)非阻塞版本的wait功能,也能支持作業(yè)控制。實(shí)際上wait函數(shù)只是waitpid函數(shù)的一個(gè)特例,在Linux內(nèi)部實(shí)現(xiàn)wait函數(shù)
19、時(shí)直接調(diào)用的就是waitpid函數(shù)。6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建wait和waitpid (2)wait和waitpid函數(shù)格式說明wait函數(shù)的語法規(guī)范如下所示。 頭文件#include #include 函數(shù)原型pid_t wait(int *status) /*等待子進(jìn)程結(jié)束,同時(shí)接受子進(jìn)程退出時(shí)的狀態(tài)*/pid_t waitpid(pid_t pid, /*等待結(jié)束的進(jìn)程類型*/ int *status, /*同wait*/ int options) /*選項(xiàng)*/這里的status若為空,則不保存子進(jìn)程退出狀態(tài);pid代表指定的子進(jìn)程。大于0時(shí)為進(jìn)程號(hào),具體見下表
20、6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建wait和waitpid (2)wait和waitpid函數(shù)格式說明 Status for traced children which have stopped is provided even if this option is not specified. 函數(shù)返回值 成功:子進(jìn)程的進(jìn)程號(hào)或0(調(diào)用成功但子進(jìn)程還未退出)失敗:-1v#include v#include vmain()vvpid_t result, pr;vresult = fork();vif(result 0)vprintf(Error occured on forkin
21、g.n);velsevif(result = 0)vsleep(10);vreturn 0;vvdovpr = waitpid(result, NULL, WNOHANG);vif(pr = 0)vprintf(No child exitedn);vsleep(1);vvwhile(pr = 0);vif(pr = result)vprintf(successfully get child %dn, pr);velsevprintf(some error occuredn);vreturn 0;v進(jìn)程組IDv每個(gè)進(jìn)程都屬于一個(gè)進(jìn)程組。每個(gè)進(jìn)程組有一個(gè)領(lǐng)頭進(jìn)程。進(jìn)程組是一個(gè)或多個(gè)進(jìn)程的集合,通常
22、它們與一組作業(yè)相關(guān)聯(lián),可以接受來自同一終端的各種信號(hào)。每個(gè)進(jìn)程組都有唯一的進(jìn)程組ID(整數(shù),也可以存放在pid_t類型中)。進(jìn)程組由進(jìn)程組ID來唯一標(biāo)識(shí)。 6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建vwait和waitpid v(3)waitpid使用實(shí)例vwait函數(shù)的使用非常簡單,只需要在父進(jìn)程處調(diào)用即可。調(diào)用wait后父進(jìn)程就會(huì)阻塞自己,直到有相應(yīng)的子進(jìn)程退出為止。waitpid函數(shù)支持不同的參數(shù),可以通過指定WNOHANG使父進(jìn)程以非阻塞的方式檢查子進(jìn)程是否結(jié)束,其調(diào)用過程如下所示:v/*調(diào)用waitpid,且父進(jìn)程不阻塞*/vpr=waitpid(pid,NULL,WNOHA
23、NG);6.2 Linux進(jìn)程控制相關(guān)APIv進(jìn)程的創(chuàng) 建避免僵死進(jìn)程實(shí)例v當(dāng)一個(gè)進(jìn)程已經(jīng)終止,但是其父進(jìn)程尚未對其進(jìn)行回收(獲得終止子進(jìn)程的有關(guān)信息,釋放它占用的資源)的進(jìn)程被稱為僵死進(jìn)程。v為了避免僵死進(jìn)程的出現(xiàn),一種辦法是父進(jìn)程調(diào)用wait/waitpid等待子進(jìn)程結(jié)束,但這樣做有一個(gè)弊端就是在子進(jìn)程結(jié)束前父進(jìn)程會(huì)一直阻塞,不能做任何事情。另外一種更好的方法就是調(diào)用兩次fork函數(shù)。 int main() pid_t pid; if(pid = fork() 0) / 創(chuàng)建子進(jìn)程1 perror(fork); else if(pid = 0) / 子進(jìn)程1 if(pid = fork()
24、 0) sleep(1);exit(0); / 子進(jìn)程1結(jié)束 else / 子進(jìn)程2 sleep(2); /*打印子進(jìn)程2的父進(jìn)程號(hào)*/ printf(second child, parent pid = %dn, getppid(); exit(0); else / 父進(jìn)程 / do something else 練習(xí)編寫程序?qū)崿F(xiàn)5次循環(huán)輸出“child process replaced”,然后退出,作為子進(jìn)程的代碼。然后編寫程序創(chuàng)建子進(jìn)程,然后調(diào)入子進(jìn)程代碼,在父進(jìn)程輸出“parent process”8次,并用wait回收子進(jìn)程的資源。子進(jìn)程對應(yīng)的文件名及保存位置自定。6.3 ARM L
25、inux進(jìn)程間通信vLinux下的進(jìn)程通信方式基本上是從Unix平臺(tái)上繼承而來的。v而對Unix發(fā)展做出重大貢獻(xiàn)的兩大主力AT&T的貝爾實(shí)驗(yàn)室及BSD在進(jìn)程間的通信方面的側(cè)重點(diǎn)有所不同。v前者是對Unix早期的進(jìn)程間通信手段進(jìn)行了系統(tǒng)的改進(jìn)和擴(kuò)充,形成了“System V IPC”,其通信進(jìn)程主要局限在單個(gè)計(jì)算機(jī)內(nèi);后者則跳過了該限制,形成了基于套接口(socket)的進(jìn)程間通信機(jī)制。最初Unix的進(jìn)程間通信 基于 Socket 進(jìn)程間通信 基于 System V 進(jìn)程間通信 POSIX 進(jìn)程間通信 Linux 進(jìn)程間通信 6.3 ARM Linux進(jìn)程間通信v Unix 進(jìn)程間通信(
26、IPC)方式包括管道、FIFO、信號(hào)。v System V進(jìn)程間通信(IPC)包括System V消息隊(duì)列、System V信號(hào)燈、System V共享內(nèi)存區(qū)。v Posix 進(jìn)程間通信(IPC)包括Posix消息隊(duì)列、Posix信號(hào)燈、Posix共享內(nèi)存區(qū)。 v現(xiàn)在在主要Linux中使用較多的進(jìn)程間通信方式有以下幾種。(1)管道(Pipe)及有名管道(named pipe)(2)信號(hào)(Signal)(3)消息隊(duì)列(4)共享內(nèi)存(5)信號(hào)量(6)套接字(Socket)6.3.1 管道通信v管道概述 v管道是Linux中進(jìn)程間通信的一種方式,它把一個(gè)程序的輸出直接連接到另一個(gè)程序的輸入。Linu
27、x的管道主要包括兩種:無名管道有名管道。無名管道 v無名管道是Linux中管道通信的一種原始方法,如圖6.4所示,它具有如下特點(diǎn)。它只能用于具有親緣關(guān)系的進(jìn)程之間的通信(也就是父子進(jìn)程或者兄弟進(jìn)程之間)。它是一個(gè)半雙工的通信模式,具有固定的讀端和寫端。管道也可以看成是一種特殊的文件,對于它的讀寫也可以使用普通的read、write等函數(shù)。但是它不是普通的文件,并不屬于其他任何文件系統(tǒng),并且只存在于內(nèi)存中。 fd0 子進(jìn)程 父進(jìn)程 fd1 內(nèi)核 無名管道 無名管道v因?yàn)閜ipe存在于內(nèi)存中,所以無法像操作普通文件那樣通過指定路徑來打開文件。通常的做法是在父進(jìn)程中創(chuàng)建管道,再創(chuàng)建子進(jìn)程。由于子進(jìn)程
28、繼承了父進(jìn)程打開的文件描述符,所以父子進(jìn)程就可以通過創(chuàng)建的管道進(jìn)行通信。v為了在父進(jìn)程中創(chuàng)建管道,需要先定義一個(gè)包含兩個(gè)元素的整型數(shù)組,用來存放管道讀端和寫端對應(yīng)的文件描述符。該數(shù)組在創(chuàng)建管道時(shí)作為參數(shù)傳遞。v其中數(shù)組的第一個(gè)元素固定代表管道的讀端,第二個(gè)元素代表管道的寫端。對于一個(gè)進(jìn)程來說,只會(huì)用到其中一個(gè)。v若讀取管道時(shí)沒有數(shù)據(jù),則進(jìn)程會(huì)被阻塞,直到有數(shù)據(jù)可讀。寫管道時(shí)除非管道已滿,一般情況下寫入操作很快會(huì)返回。pipevpipe(建立管道):1) 頭文件 #include2) 定義函數(shù): int pipe(int filedes2);3) 函數(shù)說明: pipe()會(huì)建立管道,并將文件描述
29、詞由參數(shù)filedes數(shù)組返回。 filedes0為管道里的讀取端 filedes1則為管道的寫入端。4) 返回值: 若成功則返回零,否則返回-1,錯(cuò)誤原因存于errno中。 v#include v#include v#include v#define MAXLINE 80vint main(void)vvint n;vint fd2;vpid_t pid;vchar lineMAXLINE;vif (pipe(fd) 0) vperror(pipe);vexit(1);vvif (pid = fork() 0) / 0) /* * parent parent * */ /close(fd0)
30、;close(fd0);printf(parent process,writeprintf(parent process,write pipen);pipen);write(fd1, hello worldn, 12);write(fd1, hello worldn, 12);wait(NULLwait(NULL);); else / else /* * child child * */ /close(fd1);close(fd1);n = read(fd0, line, MAXLINE);n = read(fd0, line, MAXLINE);printf(child process,re
31、adprintf(child process,read pipen); pipen);write(STDOUT_FILENOwrite(STDOUT_FILENO, line, n);, line, n); return 0;return 0; 有名管道(FIFO) v有名管道是對無名管道的一種改進(jìn),如圖6.5所示,它具有如下特點(diǎn):它可以使互不相關(guān)的兩個(gè)進(jìn)程實(shí)現(xiàn)彼此通信。該管道可以通過路徑名來指出,并且在文件系統(tǒng)中是可見的。在建立了管道之后,兩個(gè)進(jìn)程就可以把它當(dāng)作普通文件一樣進(jìn)行讀寫操作,使用非常方便。FIFO嚴(yán)格地遵循先進(jìn)先出規(guī)則,對管道及FIFO的讀總是從開始處返回?cái)?shù)據(jù),對它們的寫則把數(shù)據(jù)
32、添加到末尾,它們不支持如lseek()等文件定位操作。 fd0 進(jìn)程 2 進(jìn)程 1 fd1 內(nèi)核 有名管道 6.3.1 管道通信v有名管道的創(chuàng)建(1)函數(shù)說明有名管道的創(chuàng)建可以使用函數(shù)mkfifo,該函數(shù)類似文件中的open操作,可以指定管道的路徑和讀寫權(quán)限。普通文件在讀寫時(shí)不會(huì)出現(xiàn)阻塞問題,而在管道的讀寫中卻有阻塞的可能。這里的非阻塞標(biāo)志可以在open函數(shù)中設(shè)定為O_NONBLOCK。 v 對于讀進(jìn)程v 若該管道是以阻塞方式打開,若當(dāng)前FIFO內(nèi)沒有數(shù)據(jù),則讀進(jìn)程將一直阻塞,直到有數(shù)據(jù)寫入。v 若該管道是以非阻塞方式打開,則不論FIFO內(nèi)是否有數(shù)據(jù),讀進(jìn)程都會(huì)立即執(zhí)行讀操作。v 對于寫進(jìn)程v
33、 若該管道是以阻塞方式打開,則寫進(jìn)程將一直阻塞直到有讀進(jìn)程讀出數(shù)據(jù)。v 若該管道是以非阻塞方式打開,則無論當(dāng)前FIFO內(nèi)有沒有讀操作,寫進(jìn)程都會(huì)立即執(zhí)行寫操作 6.3.1 管道通信v有名管道的創(chuàng)建v(2)函數(shù)格式定義mkfifo函數(shù)格式如下所示: 頭文件v#include v#include 函數(shù)原型vint mkfifo(const char *filename, /* 要?jiǎng)?chuàng)建的管道*/v mode_t mode) /*管道文件的讀寫權(quán)限*/ 函數(shù)返回值v成功:0v出錯(cuò):-16.3.1 管道通信v有名管道的創(chuàng)建v(3)函數(shù)調(diào)用實(shí)例若要使用有名管道的方式來進(jìn)行進(jìn)程間通信,則必須首先調(diào)用mkfi
34、fo函數(shù)創(chuàng)建管道,創(chuàng)建后用戶可以調(diào)用函數(shù)open、read、write來實(shí)現(xiàn)對管道的讀寫,如下所示:/*創(chuàng)建有名管道,并設(shè)置相應(yīng)的權(quán)限*/mkfifo(FIFO,0666);/*打開有名管道,并設(shè)置非阻塞標(biāo)志*/fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);6.3.2 信號(hào)通信v信號(hào)概述信號(hào)是進(jìn)程間通信機(jī)制中惟一的異步通信方式,可以看作是異步通知,通知接收信號(hào)的進(jìn)程有哪些事情發(fā)生了。信號(hào)事件的發(fā)生有兩個(gè)來源:硬件來源(比如我們按下了鍵盤或者其他硬件故障);軟件來源,最常用發(fā)送信號(hào)的系統(tǒng)函數(shù)是kill、raise、alarm、setitimer和sigqueue函數(shù),軟
35、件來源還包括一些非法運(yùn)算等操作。進(jìn)程可以通過3種方式來響應(yīng)一個(gè)信號(hào)。v(1)忽略信號(hào)v(2)捕捉信號(hào)v(3)執(zhí)行缺省操作6.3.2 信號(hào)通信v信號(hào)概述一個(gè)完整的信號(hào)生命周期可以分為3個(gè)階段。這3個(gè)階段由4個(gè)重要事件來刻畫的:信號(hào)產(chǎn)生、信號(hào)在進(jìn)程中注冊、信號(hào)在進(jìn)程中注銷、執(zhí)行信號(hào)處理函數(shù)。 內(nèi)核進(jìn)程 信號(hào)產(chǎn)生 信號(hào)處理 用戶進(jìn)程 信號(hào)注冊 信號(hào)注銷 6.3.2 信號(hào)通信v信號(hào)概述信號(hào)的處理包括信號(hào)的發(fā)送、捕獲以及信號(hào)的處理,它們各自相對應(yīng)的常見函數(shù)有v發(fā)送信號(hào)的函數(shù):kill()、raise()。v捕獲信號(hào)的函數(shù):alarm()、pause()。v設(shè)置信號(hào)處理的函數(shù):signal()。6.3.2
36、 信號(hào)通信vkill()和raise() (1)函數(shù)說明kill函數(shù)可以發(fā)送信號(hào)給進(jìn)程或進(jìn)程組。它不僅可以中止進(jìn)程,也可以向進(jìn)程發(fā)送其他信號(hào)。與kill函數(shù)所不同的是,raise函數(shù)只允許進(jìn)程向自身發(fā)送信號(hào)。(2)函數(shù)格式kill和raise函數(shù)的語法要點(diǎn)如下所示。 頭文件#include #include 函數(shù)原型int kill(pid_t pid, /*指明要接收信號(hào)的進(jìn)程號(hào)*/ int sig) /*信號(hào),表6.4中的數(shù)值*/int raise(int sig) /*信號(hào),表6.4中的數(shù)值*/SIGHUP本信號(hào)在用戶終端連接(正常或非正常)結(jié)束時(shí)發(fā)出, 通常是在終端的控制進(jìn)程結(jié)束時(shí),
37、通知同一session內(nèi)的各個(gè)作業(yè), 這時(shí)它們與控制終端不再關(guān)聯(lián)。對于與終端脫離關(guān)系的守護(hù)進(jìn)程,這個(gè)信號(hào)用于通知它重新讀取配置文件。SIGINT程序終止(interrupt)信號(hào), 在用戶鍵入INTR字符(通常是Ctrl-C)時(shí)發(fā)出,用于通知前臺(tái)進(jìn)程組終止進(jìn)程。SIGQUIT和SIGINT類似, 但由QUIT字符(通常是Ctrl-)來控制. 進(jìn)程在因收到SIGQUIT退出時(shí)會(huì)產(chǎn)生core文件, 在這個(gè)意義上類似于一個(gè)程序錯(cuò)誤信號(hào)。SIGILL執(zhí)行了非法指令. 通常是因?yàn)榭蓤?zhí)行文件本身出現(xiàn)錯(cuò)誤, 或者試圖執(zhí)行數(shù)據(jù)段. 堆棧溢出時(shí)也有可能產(chǎn)生這個(gè)信號(hào)。SIGFPE在發(fā)生致命的算術(shù)運(yùn)算錯(cuò)誤時(shí)發(fā)出.
38、不僅包括浮點(diǎn)運(yùn)算錯(cuò)誤, 還包括溢出及除數(shù)為0等其它所有的算術(shù)的錯(cuò)誤。SIGKILL用來立即結(jié)束程序的運(yùn)行. 本信號(hào)不能被阻塞、處理和忽略。如果管理員發(fā)現(xiàn)某個(gè)進(jìn)程終止不了,可嘗試發(fā)送這個(gè)信號(hào)。6.2SIGALRM時(shí)鐘定時(shí)信號(hào), 計(jì)算的是實(shí)際的時(shí)間或時(shí)鐘時(shí)間. alarm函數(shù)使用該信號(hào).SIGCHLD子進(jìn)程結(jié)束時(shí), 父進(jìn)程會(huì)收到這個(gè)信號(hào)。SIGSTOP停止(stopped)進(jìn)程的執(zhí)行. 注意它和terminate以及interrupt的區(qū)別:該進(jìn)程還未結(jié)束, 只是暫停執(zhí)行. 本信號(hào)不能被阻塞, 處理或忽略.SIGTSTP停止進(jìn)程的運(yùn)行, 但該信號(hào)可以被處理和忽略. 用戶鍵入SUSP字符時(shí)(通常是C
39、trl-Z)發(fā)出這個(gè)信號(hào)6.3.2 信號(hào)通信vkill()和raise() 函數(shù)返回值成功:0出錯(cuò):-1(3)函數(shù)調(diào)用實(shí)例這兩個(gè)函數(shù)的調(diào)用都比較簡單,如下所示:raise(SIGSTOP);kill(pid,SIGKILL);例子v創(chuàng)建子進(jìn)程,然后子進(jìn)程輸出“wait 5s”,睡眠5秒,然后殺死本進(jìn)程,父進(jìn)程輸出“parent process”,并等待子進(jìn)程結(jié)束,回收資源。#include#include#include#include#include#includeint main()pid_t pid;int status,result;result=fork();if(result=-1
40、) perror(fork); exit(-1); if(result)printf(parent processn);sleep(1);/kill(result,SIGKILL);pid=wait(&status);elseprintf(wait 5sn);raise(SIGKILL);return 0;6.3.2 信號(hào)通信valarm()和pause() (1)函數(shù)說明valarm也稱為鬧鐘函數(shù),它可以在進(jìn)程中設(shè)置一個(gè)定時(shí)器,當(dāng)定時(shí)器指定的時(shí)間到時(shí),它就向進(jìn)程發(fā)送SIGALARM信號(hào)。 一個(gè)進(jìn)程只有一個(gè)鬧鐘。vpause函數(shù)是用于將調(diào)用進(jìn)程掛起直至捕捉到信號(hào)為止。 (2)函數(shù)格式a
41、larm和pause函數(shù)的語法要點(diǎn)如下所示。 頭文件#include 函數(shù)原型unsigned int alarm(unsigned int seconds) /*指定秒數(shù)*/int pause(void)6.3.2 信號(hào)通信valarm()和pause() v 函數(shù)返回值v成功:如果調(diào)用此alarm()前,進(jìn)程中已經(jīng)設(shè)置了鬧鐘時(shí)間,則返回上一個(gè)鬧鐘時(shí)間的剩余時(shí)間,v否則返回0。v出錯(cuò):-1,并且把error值設(shè)為EINTR(3)函數(shù)調(diào)用實(shí)例v這兩個(gè)函數(shù)的調(diào)用很簡單,如下所示:vret=alarm(5);vpause();v由于SIGALARM默認(rèn)的系統(tǒng)動(dòng)作為終止該進(jìn)程,因此在收到該信號(hào)之后程
42、序就終止了。例v設(shè)置10s鬧鐘,然后睡眠5s,獲取鬧鐘剩余時(shí)間并顯示,然后設(shè)置鬧鐘為剩余時(shí)間,接著暫停進(jìn)程。#include #include int main() unsigned int timeleft; printf( Set alarm 10s and sleep 5sn ); alarm( 10 ); sleep( 5 ); timeleft = alarm( 0 ); /鑾峰緱涓婁竴涓椆閽熺殑鍓綑鏃墮棿錛?縐? printf(Time left before cancel, and rearm: %dn, timeleft);alarm( timeleft ); printf(H
43、anging around, waiting to dien);pause(); /璁繘紼嬫殏鍋滅洿鍒頒俊鍙峰嚭鐜? return 0;6.3.2 信號(hào)通信vsignal() (1)函數(shù)說明v一個(gè)進(jìn)程可以決定在該進(jìn)程中需要對哪些信號(hào)進(jìn)行什么樣的處理。v使用signal函數(shù)時(shí),只需把要處理的信號(hào)和處理函數(shù)列出即可。它主要是用于前32種非實(shí)時(shí)信號(hào)的處理,不支持信號(hào)傳遞信息。 (2)函數(shù)格式signal函數(shù)的語法要點(diǎn)如下所示。 頭文件v#include 函數(shù)原型vtypedef void (*sighandler_t)(int);/定義了一個(gè)函數(shù)指針,該函數(shù)接受一一個(gè)函數(shù)指針,該函數(shù)接受一個(gè)整型參數(shù)
44、并返回一個(gè)無類型值個(gè)整型參數(shù)并返回一個(gè)無類型值 vsighandler_t signal(int signum, sighandler_t handler); 6.3.2 信號(hào)通信vsignal() 函數(shù)返回值成功:以前的信號(hào)處理配置 出錯(cuò):-1(3)使用實(shí)例使用signal函數(shù)時(shí)通常用于自定義信號(hào)處理函數(shù)(handler的第3種情況)。首先自定義了信號(hào)處理函數(shù),接著再使用signal函數(shù)處理相應(yīng)的信號(hào)。/*這里的my_func是自定義信號(hào)處理函數(shù)*/signal(SIGINT, my_func);signal(SIGQUIT, my_func); 示例程序6.3.2 信號(hào)通信v具有超時(shí)限制的
45、read調(diào)用 通常的read函數(shù)并沒有超時(shí)限制的功能。如果讀取的設(shè)備是一個(gè)低速設(shè)備,可能需要等待一段時(shí)間才會(huì)讀取成功。這里通過使用alarm定時(shí)函數(shù)來給read函數(shù)設(shè)置超時(shí)時(shí)限(10s)。若定時(shí)器到時(shí),就會(huì)向進(jìn)程發(fā)送SIGALRM信號(hào),從而調(diào)用函數(shù)sig_alrm。int main(void) int n; char lineMAXLINE; /*設(shè)定超時(shí)時(shí)限*/ alarm(10); /*信號(hào)注冊函數(shù)*/ if(signal(SIGALRM, sig_alrm) = SIG_ERR) perror(signal); exit(-1); 6.3.2 信號(hào)通信vif(n = read(STDIN
46、_FILENO, line, MAXLINE) 0) perror(read); write(STDOUT_FILENO, line, n); exit(0);static void sig_alrm(int signo) printf(in here alarmn); exit(0); 6.3.3 共享內(nèi)存v共享內(nèi)存概述共享內(nèi)存允許兩個(gè)或更多進(jìn)程共享一給定的內(nèi)存區(qū)域。因?yàn)閿?shù)據(jù)不需要在各個(gè)進(jìn)程之間復(fù)制,所以這是最高效的一種進(jìn)程間通信方式。使用共享內(nèi)存的關(guān)鍵在于如何在多個(gè)進(jìn)程之間對一給定的存儲(chǔ)區(qū)進(jìn)行同步訪問。 6.3.3 共享內(nèi)存v函數(shù)說明 共享內(nèi)存的實(shí)現(xiàn)分為3個(gè)步驟。v第一步是創(chuàng)建共享內(nèi)存,這
47、里用到的函數(shù)是shmget,也就是從內(nèi)存中獲得一段共享內(nèi)存區(qū)域。v第二步映射共享內(nèi)存,也就是把這段創(chuàng)建的共享內(nèi)存映射到具體的進(jìn)程空間去,這里使用的函數(shù)是shmat。接著就可以使用這段共享內(nèi)存了,即可以使用不帶緩沖的I/O讀寫命令對其進(jìn)行操作。v第三步是撤銷映射的操作,其函數(shù)為shmdt。6.3.3 共享內(nèi)存v函數(shù)格式 v函數(shù)的頭文件如下所示。#include #include #include vshmget函數(shù)的語法要點(diǎn)如下所示。v 函數(shù)原型int shmget(key_t key, /*IPC_PRIVATE typedef long key_t;*/ int size, /*共享內(nèi)存區(qū)大
48、小*/ int shmflg) /*同open函數(shù)的權(quán)限位,也可以用8進(jìn)制表示法*/IPC_PRIVATE 是一個(gè)特殊的key_t 值;當(dāng)使IPC_PRIVATE 作為 key 時(shí),這個(gè)系統(tǒng)調(diào)用就會(huì)只使用 shmflg 的低 9 位。 v 函數(shù)返回值成功:共享內(nèi)存段標(biāo)識(shí)符出錯(cuò):-1IPC_PRIVATEvIPC(Inter-Process Communication,進(jìn)程間通信vIPC_PRIVATE創(chuàng)建新的IPC結(jié)構(gòu)(作為msgget,semget,shmget的參數(shù)),如果要訪問一個(gè)現(xiàn)存隊(duì)列,則不能用IPC_PRIVATE作為鍵 v使用IPC_PRIVATE創(chuàng)建的IPC對象, key值屬性
49、為0,和IPC對象的編號(hào)就沒有了對應(yīng)關(guān)系。這樣毫無關(guān)系的進(jìn)程,就不能通過key值來得到IPC對象的編號(hào)(因?yàn)檫@種方式創(chuàng)建的IPC對象的key值都是0)。因此,這種方式產(chǎn)生的IPC對象,和無名管道類似,不能用于毫無關(guān)系的進(jìn)程間通信。可以用于有親緣關(guān)系的進(jìn)程間通信。 6.3.3 共享內(nèi)存v函數(shù)格式 shmat函數(shù)的語法要點(diǎn)如下所示。 函數(shù)原型vchar *shmat(int shmid, /*要映射的共享內(nèi)存區(qū)標(biāo)識(shí)符*/v const void *shmaddr, /*將共享內(nèi)存映射到指定位置(若為0則表示把該段共享內(nèi)存映射到調(diào)用進(jìn)程的地址空間)*/v int shmflg) /*SHM_RDON
50、LY:共享內(nèi)存只讀。默認(rèn)0,共享內(nèi)存可讀寫*/ 函數(shù)返回值v成功:被映射的段地址v出錯(cuò):-1shmdt函數(shù)的語法如下所示。 函數(shù)原型vint shmdt(const void *shmaddr) /*被映射的共享內(nèi)存段地址*/ 函數(shù)返回值v成功:0v出錯(cuò):-16.3.3 共享內(nèi)存v使用實(shí)例 這里要介紹的一個(gè)命令是ipcs,這是用于顯示進(jìn)程間通信狀態(tài)的命令。它可以查看共享內(nèi)存、消息隊(duì)列等各種進(jìn)程間通信機(jī)制對象的情況,這里使用了system函數(shù)來調(diào)用命令ipcs,函數(shù),如下所示:v/*創(chuàng)建共享內(nèi)存*/vshmget(IPC_PRIVATE,BUFSZ,0666);v/*映射共享內(nèi)存*/vshmat
51、(shmid,0,0);v/*刪除共享內(nèi)存*/vshmdt(shmadd);v應(yīng)用示例應(yīng)用示例 首先創(chuàng)建一個(gè)共享區(qū),然后查看其信息,最后刪除首先創(chuàng)建一個(gè)共享區(qū),然后查看其信息,最后刪除shmid_dsv內(nèi)核為每一個(gè)共享內(nèi)存段維護(hù)著一個(gè)特殊的數(shù)據(jù)結(jié)構(gòu),就是shmid_ds,這個(gè)結(jié)構(gòu)在include/linux/shm.h中定義 vstruct shmid_ds struct ipc_perm shm_perm;/* 操作權(quán)限*/ int shm_segsz; /*段的大小(以字節(jié)為單位)*/ time_t shm_atime; /*最后一個(gè)進(jìn)程附加到該段的時(shí)間*/ time_t shm_dtim
52、e; /*最后一個(gè)進(jìn)程離開該段的時(shí)間*/ time_t shm_ctime; /*最后一個(gè)進(jìn)程修改該段的時(shí)間*/ unsigned short shm_cpid; /*創(chuàng)建該段進(jìn)程的pid*/ unsigned short shm_lpid; /*在該段上操作的最后1個(gè)進(jìn)程的pid*/ short shm_nattch; /*當(dāng)前附加到該段的進(jìn)程的個(gè)數(shù)*/*下面是私有的*/ unsigned short shm_npages; /*段的大小(以頁為單位)*/ unsigned long *shm_pages; /*指向frames-SHMMAX的指針數(shù)組*/ struct vm_area_st
53、ruct *attaches; /*對共享段的描述*/; 6.3.4 消息隊(duì)列v消息隊(duì)列概述 消息隊(duì)列就是一個(gè)消息的鏈表。用戶可以把消息看作一個(gè)記錄,具有特定的格式以及特定的優(yōu)先級(jí)。對消息隊(duì)列有寫權(quán)限的進(jìn)程可以向中按照一定的規(guī)則添加新消息;對消息隊(duì)列有讀權(quán)限的進(jìn)程則可以從消息隊(duì)列中讀走消息,消息隊(duì)列是由內(nèi)核持續(xù)的。6.3.4 消息隊(duì)列v消息隊(duì)列實(shí)現(xiàn)說明 消息隊(duì)列的實(shí)現(xiàn)包括創(chuàng)建或打開消息隊(duì)列、添加消息、讀取消息和控制消息隊(duì)列這4種操作。 創(chuàng)建或打開消息隊(duì)列v使用函數(shù)msgget,這里創(chuàng)建的消息隊(duì)列的數(shù)量會(huì)受到系統(tǒng)消息隊(duì)列數(shù)量的限制。 添加到消息隊(duì)列v使用函數(shù)msgsnd,它把消息添加到已打開的消
54、息隊(duì)列末尾。 讀取消息隊(duì)列內(nèi)容v使用函數(shù)msgrcv,它把消息從消息隊(duì)列中取走,與FIFO不同的是,這里可以指定取走某一類型的消息。 控制消息隊(duì)列v使用函數(shù)msgctl,它可以完成多項(xiàng)功能。6.3.4 消息隊(duì)列v函數(shù)格式 v用到的頭文件如下所示:#include #include #include vmsgget函數(shù)的語法要點(diǎn)如下所示v 函數(shù)原型 功能:創(chuàng)建或獲取消息隊(duì)列標(biāo)識(shí)int msgget(key_t key, /*返回新的或已有隊(duì)列的隊(duì)列ID、IPC_PRIVATE */ int flag)v 函數(shù)返回值成功:消息隊(duì)列ID出錯(cuò):-1vmsgsnd函數(shù)的語法要點(diǎn)如下所示。v 函數(shù)原型in
55、t msgsnd(int msqid, /*消息隊(duì)列的隊(duì)列ID */ const void *prt, /*指向消息結(jié)構(gòu)的指針*/ size_t size, /*消息的字節(jié)數(shù)*/ int flag)/*取值情況:IPC_NOWAIT若消息沒有立即發(fā)送,函數(shù)立即返回。0:msgsnd阻塞直到發(fā)送完成*/6.3.4 消息隊(duì)列v這里prt消息的結(jié)構(gòu)如下所示:vstruct msgbufvlong mtype;/消息類型vchar mtextLEN;/消息正文, LEN由用戶指定vv 函數(shù)返回值v成功:0v出錯(cuò):-1vmsgrcv函數(shù)的語法要點(diǎn)如下所示。v 函數(shù)原型vint msgrcv(int ms
56、gid, /*消息隊(duì)列的隊(duì)列ID */v struct msgbuf *msgp,/* 消息緩沖區(qū)*/v int size, /*消息的字節(jié)數(shù)*/v long msgtype, /*接收的消息類型*/v int flag) /*類型符*/v 函數(shù)返回值v成功:0v出錯(cuò):-1flag含 義MSG_NOERROR若返回的消息比size字節(jié)多,則消息就會(huì)截短到size字節(jié),且不通知消息發(fā)送進(jìn)程IPC_NOWAIT若消息并沒有立即發(fā)送而調(diào)用進(jìn)程會(huì)立即返回0msgsnd調(diào)用阻塞直到條件滿足為止取值含 義0接收第一條消息大于0第一條類型為msgtype的消息小于0第一條類型為不小于msgtype的絕對值且
57、最小的消息6.3.4 消息隊(duì)列vmsgctl函數(shù)的語法要點(diǎn)如下所示。v 函數(shù)原型vint msgctl(int msgqid, /*消息隊(duì)列的隊(duì)列ID*/v int cmd, /*消息隊(duì)列控制選項(xiàng)*/v struct msqid_ds *buf ) /*消息隊(duì)列緩沖區(qū)*/v 函數(shù)返回值v成功:0v出錯(cuò):-1cmd含 義IPC_STAT讀取消息隊(duì)列的數(shù)據(jù)結(jié)構(gòu)msqid_ds,并將其存儲(chǔ)在buf指定的地址中IPC_SET設(shè)置消息隊(duì)列的數(shù)據(jù)結(jié)構(gòu)msqid_ds中的ipc_perm元素的值,這個(gè)值取自buf參數(shù)IPC_RMID從系統(tǒng)內(nèi)核中移走消息隊(duì)列msqid_ds結(jié)構(gòu) vstruct msqid_d
58、s struct msqid_ds struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue,unused */ struct msg *msg_last; /* last message in queue,unused */ _kernel_time_t msg_stime; /* last msgsnd time */ _kernel_time_t msg_rtime; /* last msgrcv time */ _kernel_time_t msg_ctime; /* last change t
59、ime */ unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */ unsigned long msg_lqbytes; /* ditto */ unsigned short msg_cbytes; /* current number of bytes on queue */ unsigned short msg_qnum; /* number of messages in queue */ unsigned short msg_qbytes; /* max number of bytes on queue */ _kern
60、el_ipc_pid_t msg_lspid; /* pid of last msgsnd */ _kernel_ipc_pid_t msg_lrpid; /* last receive pid */;ftokv獲取系統(tǒng)建立IPC通訊 (消息隊(duì)列、信號(hào)量和共享內(nèi)存) 時(shí)的ID值。v頭文件#include #include v函數(shù)原型:key_t ftok( const char * fname, int id )fname就是你指定的文件名(已經(jīng)存在的文件名),一般使用當(dāng)前目錄id是子序號(hào)。int型,但只使用8bits(1-255)。msgid=ftok( “.”, 26 ) ;6.3.4 消息隊(duì)列v使用實(shí)例在使用消息隊(duì)列前,可以先使用函數(shù)ft
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年注會(huì)考試內(nèi)容概述試題及答案
- 行政管理師考試的重要信息來源及試題及答案
- 2024年項(xiàng)目管理模擬測試試題及答案
- 2025年國際金融理財(cái)師考試資產(chǎn)保全與增值試題及答案
- 2024年微生物檢測的法規(guī)解讀試題及答案
- 2025年國際金融理財(cái)師考試職業(yè)現(xiàn)狀試題及答案
- 惠州酒店亮化施工方案
- 2024項(xiàng)目管理執(zhí)行效果試題及答案
- 微生物檢驗(yàn)技術(shù)人員的職業(yè)發(fā)展方向試題及答案
- 整合資料2025年國際金融理財(cái)師試題及答案
- 2025-2031年中國竹鼠養(yǎng)殖及深加工行業(yè)投資研究分析及發(fā)展前景預(yù)測報(bào)告
- 2025年高考數(shù)學(xué)模擬卷2(新高考Ⅱ卷專用)(解析版)
- CNAS-CC160大型活動(dòng)可持續(xù)性管理體系審核及認(rèn)證的能力要求
- 2024-2025學(xué)年人教部編版新教材語文一年級(jí)下冊第四、第五單元檢測題附答案(各一套)
- 線束培訓(xùn)計(jì)劃方案模板
- 2025年第三方支付行業(yè)市場分析報(bào)告
- 2025-2030全球氫燃料電池膜電極組件行業(yè)調(diào)研及趨勢分析報(bào)告
- GB/T 20717-2024道路車輛牽引車和掛車之間的電連接器(15芯)24 V15芯型
- 與食品安全相關(guān)的組織機(jī)構(gòu)設(shè)置,部門及崗位職責(zé)
- 《油井參數(shù)遠(yuǎn)程監(jiān)控》課件
- 中國百日咳診療與預(yù)防指南(2024版)
評(píng)論
0/150
提交評(píng)論