




下載本文檔
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、Linux3+1 暑期學習總結三(Posix 消息隊列)王晶晶一,消息隊列簡介:消息隊列可以看作是一個消息連表。它具有隨內核的持續性,即當使用該消息隊列的進程結束,或者已關閉該消息隊列,該隊列中的消息不會隨之消失,只有在內核重新初始化,即計算機重啟之后才會消失,因此稱為隨內核的持續性,這點也是與管道和 FIFO 的區另 I。消息隊列的另一個特性是,在某一個進程往消息隊列寫消息之前不需要另外某個進程在該消息隊列上等待消息的到達,即不會像管道個 FIFO 那樣,如果往管道或者 FIFO 中些數據時,如果沒有一個進程已經將讀端打開,那么寫操作會被阻塞。當然,如果從消息隊列讀取數據時,消息隊列為空是會
2、阻塞的。每個消息都是一條記錄,它有發送者賦予一個優先權,值越大優先級越高。下圖為一個消息隊列可能的布局:該鏈表的頭中含有當前隊列的兩個屬性:隊列中允許的最大消息數,每個消息的最大大小。二,相關函數解釋:1.mq_open所在頭文件:#include函數原型:mqd_tmq_open(constchar*name,int0flag,.mode_tmode,structmq_attr*attr);函數功能:創建消息隊列。參數說明:name 為消息隊列的名字,根據消息隊列的規則,為了更好的可移植性,該名字必須以,/所頭,創建一個消息隊列的時候無須路徑,給出名字就好,其存放位置可有自己指定(創建前后都
3、可以,下面會講到)。oflag:為 O_RDONLY(只讀),O_WRONLY(只寫),O_RDWR(可讀可寫)之一,可能安位或上 O_CREATE,O_EXCL(當消息已存在時,返回 EEXIST 錯誤到 errno 中),O_NONBLOCK(設置非阻塞)。mode 和 attr 參數是可選,但是當實際操作是創建一個新隊列時,即 O_CREATE 已指定,且要求創建的消息隊列不存在,mode 和 attr 參數是需要的。mode:表示創建消息對列的權限。由S_IRUSR,S_IWUSR,S_IXUSR,S_IRGRP,S_IWGRP,S_IXGRP,S_IROTH,S_IWOTH,S_IX
4、OTH相或組成或者寫成 0777(表示 rwxrwxrwx)等用八進制表示也可以。attr:在 linux 內核源代碼中 struct_mqattr 定義的源代碼如下:structmq_attrlongtongmq_inaxiTisg;longmq.msgsize;longrinsgs;lungreserved;存放消息隊列的屬性。其中 mq_flags 為 0,表示阻塞,為 O_NONBLOCK 為非阻塞。函數返回值:在內核源代碼中 mqd_t 類型的定義如下:typedef_kernel_mqd_tmqd_t;typedefint_kernel_mqd_t;若創建成功則返回消息隊列的描述符
5、,否則返回一 1。所在頭文件:#include函數原型:intmq_close(mqd_tmqdes);函數功能:關閉已打開的消息隊列,關閉后調用進程不可以再使用該描述符,但其消息隊列并沒有被刪除。一個進程終止時,它的所有打開著的消息隊列都關閉,就像調用了mq_close 一樣。參數說明:mqdes 為消息隊列的描述符,即消息隊列創建成功后的返回值。返回值:成功返回 0,失敗返回-1。3 .mq_unlink 函數所在頭文件:#include函數原型:intmq_unlink(constchar*name);函數作用:從系統中刪除名為 name 的消息隊列。但刪除的只是我們可以在系統中看見的文
6、件的名字,但文件本身并沒有被從磁盤上刪除,除非該名稱是文件的最后一個鏈接,并且該文件已關閉,才會將該文件真正從磁盤上刪除。即如果某前該詳細隊列的文件還在其他進程中打開,那么不會將其從磁盤上刪除,又或者這是最后一個鏈接,但它還為關閉,即未執行 ma_close 操作,或打開它的進程為結束就執行 mq_unlink,它也不會從磁盤上刪除。函數的參數:消息隊列的名稱,以,/叫始。函數的返回值:成功返回 0,出錯返回一 1。4 .mq_getattr 函數所在頭文件:#include函數原型:intmq_getattr(mqd_tmqdes,structmq_attr*attr);函數功能:獲取 mq
7、des 指的消息隊列的屬性,存放到 attr 結構體中。參數說明:mqdes 為消息隊列描述符,attr 為上面解釋的存放消息隊列屬性的結構體。函數返回值:成功返回 0,失敗返回一 1。5 .mq_setattr 函數:所在頭文件:#include函數原型:intmq_setattr(mqd_tmqdes,conststructmq_attr*attr,structmq_attr*oattr);函數功能:設置消息隊列的屬性,但是只使用 attr 結構體中的 mq_flags 屬性,以設置(O_NONBLOCK)或清除(0)非阻塞標志。該結構體的另外三個屬性被忽略,每個隊列的最大消息數和每個消息
8、的最大字節數都只能在創建時設置,當前隊列中的消息數是隨傳送消息和讀取消息的操作改變的,只能讀取不能設置。如果 oattr 非空,那么指定隊列的先前屬性(4個)全將返回到由該指針指向的結構體中。參數說明:見上述函數功能中對 attr 和 oattr 的解釋。返回值:成功返回 0,失敗返回一 1。6 .mq_send 函數:所在頭文件:#include函數原型:intmq_send(mqd_tmqdes,constchar*ptr,size_tlen,unsignedintprio);函數功能:給描述符 mqdes 指向的消息隊列發送消息,大小為 len,內容存放在 ptr中,prio 為優先級。
9、參數說明:mqdes 為要發送消息的消息隊列描述符,ptr 為要發送的數據,len 為消息的長度,prio 為消息的優先級。返回值:成功返回 0,失敗返回一 1。7 .mq_receive 函數:所在頭文件:#include函數原型:ssize_tmq_receive(mqd_tmqdes,char*ptr,size_tlen,unsignedint*proip);函數功能:從描述符 mqdes 指向的消息隊列中讀取消息存放 ptr 中。參數說明:mqdes 為要從中讀取消息的消息隊列的描述符,ptr 為存放接受到的消息的指針,len 為接受的最大長度,該值不能小于能加到該消息對列上的最大大小
10、,如果 len 小于該值,就立即返回 EMSGSIZE 錯誤。返回值:成功返回讀取消息的內容的字節數,出錯返回一 1。8 .mq_notify 函數:所在頭文件:#include,#include函數原型:intmq_notify(mqd_tmqdes,conststructsigevent*notification);函數功能:為指定隊列建立或刪除異步事件通知。參數說明:在中:typedefunionsigvalintsival_int;void_user*sival_ptr;sigval_t;typedefstructsigeventsigval_tsigev_value;intsigev
11、_signo;intsigev_notify;void(*sigev_notify_function)(unionsigval);Pthread_attr_t*sigev_notify_attributes;sigevent_t;(1) .如果 notification 參數非空,那么當前進程希望在有一個消息到達所指定的先前為空的隊列時得到通知。我們說該進程被注冊為接收該隊列的通知(2) .如果 notification 參數為空指針,而且當前進程目前被注冊為接收所指定隊列的通知,那么已存在的注冊將被撤銷。(3) .任意時刻只有一個進程可以被注冊為接收某個指定隊列的通知。(4) .當有一個消息
12、到達某個先前為空的隊列,而且已有一個進程被注冊為接收該隊列的通知時,只有在沒有任何線程阻塞在該隊列的 mq_receive 調用中的前提下,通知才會發出。這就是說,在 mq_receive 調用中的阻塞比任何通知的注冊都優先。(5) .當該通知被發送給它的注冊進程時,其注冊即被撤銷。該進程必須再次調用 mq_notify重新注冊(如果想要的話)。返回值:成功返回 0,失敗返回一 1。三,相關程序示例:mq_create.c#include#include#include#include#include#include#includestructmq_attrattr;intmain(intar
13、gc,char*argv)intc,flags;mqd_tmqd;flags=O_RDWR|O_CREAT;/emz 表示命令行的選項,m 和 z 帶有參數,getopt 在我博客有詳解while(c=getopt(argc,argv,em:z:)!=-1)switch(c)casee:flags|=O_EXCL;break;casem:attr.mq_maxmsg=atol(optarg);break;casez:attr.mq_msgsize=atol(optarg);break;if(optind!=argc-1)(perror(optinderror!n);)if(attr.mq_ma
14、xmsg!=0&attr.mq_msgsize=0)|(attr.mq_maxmsg=0&attr.mq_msgsize!=0)(perror(mustspecifyboth-mmaxmsgand-zmsgsize!n);)mqd=mq_open(argvoptind,flags,0644,(attr.mq_maxmsg!=0)?&attrNULL);if(mqd!=-1)printf(createok!n);mq_close(mqd);/mq_close 只是關閉了描述符,并不刪除消息隊列)elseprintf(createerror!n);exit(0);運行過程及
15、結果:wjJBpanda-G31M-ES2C:/linuxJ+1ZtestCode/PosixSwjjfpanda-63lM-ES2C:/linux3+1/testCode/PosixScreateerror!wjjtpanda-G31MES2C/llnux5+1/testCode/PosixtwjjPpanda-1M-ES2C:/linux54-1/testCode/Posixt8192wjjBpanda-631R-ES2Cr/linuxS+1/testCode/Posixtcreateerror!wjjfpanda-GJ1M-ES2C:/linuxS+1ZtestCode/Posixtcr
16、eateok!wjjtpandd-G31M-ES2C:/linuxl+1/testCode/PosixS從上可以看出,創建一個消息隊列時,其最大消息數和每個消息的最大字節數不能超出,系統的 msg_max 和 msgsize_max,否則創建失敗。當然每個系統對應的這兩個值都不同,可通過上面的 cat 路徑進行查看。/mq1 創建失敗是因為在這之前已經創建了一個/mq1,e 選項就是用來判斷當創建的消息隊列存在時,返回錯誤信息。編譯時在最后一定要加上-Irt,表示鏈接。在消息隊列的名字前一定要加/,這是 Posix 的規定,為了更好的可移植性。接下來我們要對消息隊列進行掛載,只有掛載后你才能看
17、見你的消息隊列:gccmqcreate,c-omqcreate-Irt./iriqcreate-e-m3r1B24cat/proc/sys/f5/mqueue/m$g,maxcat/proc/sys/fs/mqueue/msgsize_iiiax.Zmqcreate-e-m8-z1024/mql./mqcreate-e-m8-z1024/mq2文件舊編輯舊查看忖搜索文件舊編輯舊查看忖搜索終端終端幫則幫則H)rootepanda-G31M-ES2C:/home/wjj/linux34-Vtestcode/Posiximount-tmqueuenonemqueuerootpanda-G3IM-ES
18、2C:/home/wjj/linux54-1/testCode/PosixiexiteKitwjjpanda-G51N-ES2C:/linux3+1/testCade/Posix$Is-Inqueue總用星總用星0-rw-r-r-1wjjwjj8Q2011-08-03。9:g6mq1-1wjjB2311-98-04g:12mq2,可以看到在程序的最后調用的 mq_close,但并未刪除消息隊列的名字,只是關閉了描述符,這是 mq_close 和 mq_unlink 的最大區別。mqunlink.c#include#include#include#include#includeintmain(i
19、ntargc,char*argv)intflag;if(argc!=2)perror(usage:maunlink);flag=mq_unlink(argv1);if(flag=-1)printf(fail!n);elseprintf(ok!n);exit(0);運行過程及結果:wjj電電pan而而-GE1M-EG2c廣廣/Linux3+ItswtCod白白Posixtgccmqurlink.c-omqunlink-l.rtwjjCpanda-G31M-ES2C:/linux3+1/testCode/PosixtIs-1mqueue總用量總用量0- rw-r-r-1wjjwjj302011-0
20、8-0509:17mqi- rw-r-r-1wjjwjjB0.2011-08-03&9:12mq2wjj*panda-631M-ES2Cr/linux3+1/testCode/Posix$./mqunlinkZmqiok!wjjepanda-GilM-ES2C:/linux3+1/testcode/PosixtIs-Imqiueue總用量總用量0- rw-r-r-1wjjwjj8a2811-00-fl3。9:12叫叫2wjjepanda-G51MES2Cr/linux5+1/testCode/Posixt|mqsend.c#include#include#include#include
21、#include#include#include#includeintmain(intargc,char*argv)mqd_tmqd;char*ptr;size_tlen;unsignedintprio;if(argc!=4)perror(./mqsendmqueue_namesizeprio!n);len=atoi(argv2);prio=atoi(argv3);mqd=mq_open(argv1,O_WRONLY);ptr=(char*)calloc(len,sizeof(char);strcpy(ptr,wjj_xyd);mq_send(mqd,ptr,len,prio);exit(0)
22、;mqreceive.c#include#include#include#include#include#includeintmain(intargc,char*argv)(intc,flags;mqd_tmqd;ssize_tn;unsignedintprio;char*buff;structmq_attrattr;flags=O_RDONLY;while(c=getopt(argc,argv,n)!=-1)(switch(c)casen:flags|=O_NONBLOCK;break;if(optind!=argc-1)perror(mqreceiveerror!n);mqd=mq_ope
23、n(argvoptind,flags);mq_getattr(mqd,&attr);buff=(char*)malloc(attr.mq_msgsize);n=mq_receive(mqd,buff,attr.mq_msgsize,&prio);printf(buff=%s,read%ldbytes,priority=%un,buff,(long)n,prio);exit(0);mqsen.c 和 mqreceive.c 的運行過程和結果:卜面往一個消息隊列中寫入多條消息,然后讀取,會發現讀取的結果是按優先級從高到低(因為mq_receive 的 priop 指針不空):wjj
24、panda-G31M-ES2C:/linux3+1ZtestCode/Posixt./inqsend/mql10012wjjSpanda-G31M-ES2C:/linuxS+1/testCode/Posix$./inqsend/mql5。6wjjCpanda-631M-ES2C:/linuxS+1ZtestCode/PosixJ./mqsend/mql568wjjpanda-G31M-ES2C:/linux34-1/testCode/Posix$,/mqreceice/mqlbuff=wjj_xyd,read100bytes,priority-12wjjpanda-G31H-ES2C:Zlin
25、ux3+1/testCode/PosixS,/mqreceice/mqlbuff-wjj_xyd,read50bytes,priority=8wjjepanda-G31H-ES2C:/linuxS+1/testCode/Posix$./mqreceice/mqlbuff=wjj_xyd,read5。bytes,priority=6wjjSpanda-G31M-ES2C:/linuxS+1/testCode/Posixt|下來是一個簡單的信號通知的程序,通過 mq_notify 函數實現:mqnotifysigl.c:#include#include#include#include#includ
26、e#includemqd_tmqd;void*buff;structmq_attrattr;structsigeventsigev;staticvoidsig_usr1(int);wjjpanda-G31M-ES2C:/linuxJ+17testcode/PosixSwjjflpanda-G31M-ES2C:/linux3+Vtestcode/Posixlwjjfpanda-G31M-ES2:/linuxi+1/testCode/Poslxl總用量總用量0- rw*r-r-1wjjwjj802011-6B-0369:12mq2- rw-r-r-1wjjwjj802011-08-0389:28m
27、q3wjjpanda-G3lH-ES2C:/linux3+1/testCode/Posixicreateok!wjjBpanda-G31M-ES2C:/linuxi4-1/testcode/PosixSwjjpanda-G31H-ES2C:/linux3+1/testcode/Posix(wjj#panda*G5iH-ES2C/LinuxS+1/testCode/Posix$wjjBpanda-G3IM-ES2C:/liilUxi4-1ZtestCode/PosixS總用量總用量0- rw*r-r-1wjjwjj8ft?0il-08-0369:50mqi- rw-r-r-1wjjwjj8020
28、11-08-0309:30mq2- rw-r-r-1wjjwjj802011-08-0509:58mq3wjjflpanda-G31M-ES2Ci/Unux3+1/testcode/Posixfbuff=wjj_xyd,read100bytes,priority=1wjjepanda-631M-ES2C;/linuxJ+1/testcode/Posix$buff=wjj_xydfread51bytespriority=1wjj8panda-G31M-ES2C:/linuxi4-1ZtestCode/PosixSbuff=wjj_xyd,read100bytes*priority=IBwjjCp
29、anda-631M-ES2C:/linux3+1/testCode/Poslxfgccmqsend.c-omqsend-Irtgccmqreceice.c-omqreceice-IrtIs-Imqueue./mqcreate/mql./mqsend/mql1001./mqsend/mqj5812./mqsend/ql10018Is-Imqueue./mqreceice/mql./mqreceice/mq2./mqreceiceZmq3intmain(intargc,char*argv)(if(argc!=2)perror(argumenterror!n);mqd=mq_open(argv1,O
30、_RDONLY);mq_getattr(mqd,&attr);/獲取屬性buff=malloc(attr.mq_msgsize);signal(SIGUSR1,sig_usr1);/接收到 SIGUSR1 信號后,執行 sig_usr1 函數sigev.sigev_notify=SIGEV_SIGNAL;sigev.sigev_signo=SIGUSR1;mq_notify(mqd,&sigev);/注冊for(;)(printf(dddddn);sleep(3);/pause();exit(0);staticvoidsig_usr1(intsigno)(ssize_tn;mq
31、_notify(mqd,&sigev);/重新注冊n=mq_receive(mqd,buff,attr.mq_msgsize,NULL);printf(SIGUSR1received,read%ldbytes,buff%sn,(long)n,(char*)buff);return;執行順序為:main 函數會一直往下執行,直到接收到 SIGUSR1 信號,停止當前執行的語句,立刻去執行 sig_usr1 函數,該函數執行完之后又回到 main 函數之前終止的位置繼續執行。在 main 函數中些了一個 for 循環,通過 sleep 可以觀察其結果。如果在程序執行之前,所指定的消息隊列不
32、空,它不會讀出該消息隊列的消息,即便繼續往里寫消息它也不會讀出消息,知道通過 mqreceive 程序的進程將消息隊列的消息讀完,消息隊列變成空的,再往里面寫入消息,mqnotifysigl 程序的進程才能將剛寫入的第一條消息讀出來。該程序運行時要開兩個終端,一個執行./mqnitifusigl,一個執行./mqsend 發送消息,結果如下所示:先在終端 2 往 mq1 中寫一條消息:wjjpanda-631M-ES2C:/linuxS+1/testCode/Posix$,/mqsend/mql121wjjpanda-G3IM-ES2C:/linux3+l/testCode/Posix$|然后
33、在終端 1 執行./mqnotifysiglwjjepanda-j31H-ES2C:/linux3+1/testcode/Posix$./mqnotifysigl/mqldddddddddd然后在終端 2 執行./mqsend 再發送一條信息,查看 mqnotifysigl 能否接收到:wjjepanda-G31M-ES2C:/linux3+1/testcode/Posixt./mqsend/mql121wjjfpanda-G31M-ES2C:/linuxi+VtestCode/Posix$./mqsend/mql121wjpanda-G31M-ES2C:/LinuxS+1/testCode/
34、Posixt|在終端 1 查看 mqnotifysigl 是否接收到:wjjCpanda-G31M-ES2C:/linux.34-1/testCode/Posix$,mqnotifysigl/mqldddddddddddddddddddddddddddddddddddddddd可以看出并未接收至 U。然后在終端 2,通過執行./mqreceive 將 mq1 中的消息讀完,使消息隊列變為空:wjj&panda-G31M-ES2C:/linux34-1/testcode/Posixt./mqsend/mql121wjjepanda-G31IM-E52C:/LinuxS+1ZtestCod
35、e/Posix$./mqsend/mql121wjpanda-G31M-E52C:/linux3+VtestCode/Posixi./mqreceice/mqlbuff=wjj,xyd,read11bytes,priority=1wjj0panda-G31M-ES2C:/linuxS+1/testCode/Posix$./mqreceice/mqlbuff=wjj_xydHread12bytes,priority二1wjjepanda-G31M-ES2C:/linuxJ+1/testCode/Posixt./mqreceice/mqlACwjjpanda-G31M-ES2C:/linux3+1
36、/testCode/Posixt|然后再在終端 2 執行./mqsend 給 mql 發送一條消息(此時該消息隊列已經為空了):wjjpanda-G31M-ES2C:/Linux?+1/testCode/Po$ix$./mqsend/mqlvi1wjj(panda-G31M-ES2C/Linux3+1/testCode/Posix$4/mqreceice/mqlbuff=wjj_xyd(read12bytes,priority=1wjjpanda-G31M-ES2C:/linuxS+1/testeode/Posixi./mqreceice/mqlbuff=wjj_xyd,read12bytes,priority=1wjjCpanda-631M-ES2C:/1inux3+1/tes
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 上海汽車租賃合同協議書
- 2025年戶外廣告牌設計制作安裝合同
- 工礦產品購銷合同條例
- 藥物治療了嗎復習測試卷含答案
- 20251月合同補充的辦公區域氡氣濃度檢測條款
- 手房過戶交易合同
- 公寓地毯維修合同范本
- 甘肅省天水市12校2024-2025學年八年級下學期第一次檢測考試語文試題(含答案)
- (15)-小升初語文【多音字】通關提升訓練
- (2)-18個文言虛詞用法及舉例
- 《我不是藥神》劇本
- JJF 1101-2019《環境試驗設備溫度、濕度校準規范》規程
- 社區文體活動廣場建設項目可行性研究報告
- 新時代高職生創新創業教育PPT完整全套教學課件
- 第三章-春秋戰國時代的城市課件
- 醫務人員職業健康安全健康-課件
- 醫學文獻檢索重點
- 病區藥品規范化管理與問題對策黃池桃
- 螺紋塞規操作規程
- 2023年北京天文館招聘筆試備考題庫及答案解析
- 應急救援隊伍單兵體能訓練項目要求
評論
0/150
提交評論