高階程式設計中訊息佇列的具體使用方法

2021-07-29 19:01:39 字數 4138 閱讀 6370

每個核心中的

ipc結構(訊息佇列、訊號量或共享儲存段)都用乙個非負整數的識別符號加以引用,為了對乙個訊息佇列傳送或取訊息,只需要知道其佇列識別符號。

鍵是在使用者空間的,識別符號是在核心空間的,乙個識別符號對映乙個鍵。

使用者 核心

鍵 識別符號

1 ==> 65536

2 ==> 98305

呼叫get

函式(msgget()

、semget()

和shmget()

)時必須指定鍵表示引用哪乙個

ipc物件。

int msgget(key_t

key, int

msg***

);int semget(key_t key, int nsems

, int

sem***

);int shmget(key_t

key, size_t

size

, int

shm***);

#include 

struct  ipc_perm ;

使用ipc物件時應注意的問題:

1)程序終止了ipc物件不會被刪除,直到

1、某個程序刪除它為止

2、某個程序執行ipcrm刪除它為止

3、重新啟動作業系統。

2)這些ipc結構在檔案系統中沒有名字,於是就不得不增加新的命令ipcs和ipcrm。

訊息佇列:

訊息佇列是訊息的鏈結表,存放在

核心中並由訊息佇列識別符號標識。

msgget()用於建立乙個訊息佇列或開啟乙個現存的佇列。

msgsnd()將新訊息新增到佇列尾端。每個訊息包含乙個正長整型型別字段,乙個非負長度以及實際資料位元組,所有這些都在將訊息新增到佇列時,傳遞給msgsnd()。

msgrcv()用於從佇列中取訊息。我們不一定要以先進先出次序取訊息,也可以按訊息的型別欄位取訊息。

每個佇列都有乙個

msqid_ds

struct  msqid_ds ;

此結構規定了佇列的狀態,類似與struct  stat。

linux可傳送最長訊息的位元組數:8192位元組;

乙個特定佇列的最大位元組數:16384位元組;

系統中最大訊息佇列數:取決於作業系統;

int 

msgget(key_t 

key,int  

flag)

flag:ipc_creat,ipc_excl,許可權組合

功能:開啟乙個現存佇列或建立乙個新佇列。

若執行成功,msgget()返回訊息佇列id,此後,該值就可被用於其他三個訊息佇列函式。

建立1號訊息佇列,一定要在flag中指定ipc_creat表示建立訊息佇列,ipc_excl

表示如果訊息佇列存在則出錯返回

eexist:

if(msgq_id=msgget(1,ipc_creat|ipc_excl|0777)<0)

check_error(「msgget」);

如果已經建立訊息佇列,如何獲得訊息佇列的識別符號?

int msgq_id;

msgq_id=msgget(1,0);

int 

msgctl(int msqid,int cmd,struct  msqid_ds  *buf);

cmd引數 說明對由msqid指定的佇列要執行的命令:

ipc_stat 

取此佇列的msqid_ds結構,並將它存放在buf指向的結構中;

ipc_set 按由buf指向結構中的值,設定與此佇列相關結構中的下列四個字段:msg_perm.uid、msg_per.gid、msg_perm.mode和msg_qbytes。此命令只能由下列兩種程序執行:一種是超級使用者程序;一種是其有效使用者id等於msg_perm.cuid或msg_perm.uid的程序。

ipc_rmid 

從系統中刪除該訊息佇列以及仍在該佇列中的所有資料。此命令只能由下列兩種程序執行:一種是其有效使用者id等於msg_perm.cuid或msg_perm.uid;另一種是超級使用者程序。

例如:msgctl(1,ipc_rmid,null);

int msgsnd(int  msqid,const void *ptr,size_t  nbytes,int  flag);

成功返回0,失敗返回-1;

訊息結構體,這個結構體需要自己定義:

struct  mymesg ;

引數flag:

可以指定為ipc_nowait,這類似於檔案i/o的非阻塞標誌,若訊息佇列已滿,或佇列中的位元組總數等於系統限制值,則指定ipc_nowait使得msgsnd立即出錯返回eagain。

如果沒有指定

ipc_nowait

(通常設為0),則程序阻塞直到下述情況出現為止:

1、有空間可以容納要傳送的訊息;

2、從系統中刪除了此佇列,此時,msgsnd()返回eidrm表示該訊息佇列被刪除了。

3、捕捉到乙個訊號,並從訊號處理程式返回,此時,msgsnd()返回eintr表示被訊號中斷了。

msgsnd.c、msgrcv.c ==> 講解訊息佇列的基本使用方法。

方法:msgsnd.c向訊息佇列中傳送訊息,msgrcv.c從訊息佇列中取出訊息。

msgsnd.c

#include 

「include.h」

//定義訊息結構體

typedef struct

msg;

int main()

msgrcv.c

#include 

「include.h」

typedef struct

msg;

int main()

結果: 從訊息佇列裡拿到第2個訊息是:hello father.

訊息佇列標識==>標識訊息佇列id

訊息型別==>標識訊息id

ssize_t msgrcv(int  msqid,void *ptr,size_t  nbytes,long  type,int 

flag);

成功返回訊息的資料部分的長度,出錯返回-1.

若msgrcv成功執行時,訊息佇列中的訊息取走了就沒了。

ptr:指向乙個訊息結構體(乙個長整型數,跟隨其後的是存放實際訊息資料的緩衝區)

nbytes:資料緩衝區的長度,若返回的訊息大於nbytes,而且在flag中設定了msg_noerror,則該訊息被截短(在這種情況下,不通知我們訊息截短了,訊息的截去部分被丟棄),如果沒有設定這一標誌,而訊息又太長,則出錯返回e2big(訊息仍留在佇列中)

type==0:獲得訊息佇列中第乙個訊息

type>0 :獲得訊息佇列中型別為type的第type個訊息

type<0 :獲得訊息佇列中小於或等於type絕對值的訊息(型別最小的)

type非0用於以非先進先出次序讀訊息。

flag 

沒有設定ipc_nowait則msgrcv以阻塞方式取訊息,直到以下情況出現為止:

1、有了指定型別的訊息,則取走訊息,成功返回。

2、從系統中刪除了此佇列(出錯返回-1,errno設定為eidrm)

3、捕捉到乙個訊號並從訊號處理程式返回(msgrcv返回-1,errno設定為eintr)。

flag 

設定了ipc_nowait則msgrcv操作不阻塞,如果沒有指定型別的訊息,則msgrcv返回-1,errno設定為enomsg

練習:fork_msg.c ==> 講解訊息佇列在父子程序間通訊。

方法:父程序:傳遞2個整數放到訊息佇列裡,並把子程序運算結果從訊息佇列裡取出來

子程序:拿到父程序的2個整數進行相加把結果放回訊息列隊裡

思路:建立1號訊息佇列拿到它的核心識別符號,fork(),父程序向訊息佇列裡放2條1類訊息,每條訊息包含了乙個整數,再以阻塞方式讀取子程序放的2類訊息,子程序讀取父程序的2條1類訊息,經過計算以後放1條2類訊息放到訊息佇列裡讓父程序去取,父程序取出2類訊息列印後把訊息佇列刪除掉,並wait()子程序。

fork_msg.c

#include 

「include.h」

typedef struct

msg;

int main()

else if(pid==0)

return  0; }

訊息佇列的使用

剛開始看的時候,由兩個疑問,我自己的答案是這樣的 1.訊息佇列在系統中的最大個數,關於這個問題,書上有明確的答案 書上有個 列明了linux free bsd,mac os x solaris中的典型值。當然也可以通過一些手段來修改。sysctl就可以修改。2.在多個執行緒 或程序 同時對乙個訊息佇...

如何使用訊息佇列的事務訊息

發訊息 過程,往往是為通知另外乙個系統更新資料,mq的 事務 主要解決訊息生產者和訊息消費者的資料一致性問題。先把商品加到購物車 然後幾件商品一起下單 最後支付 完成購物流程,就可以愉快地等待收貨 該過程中有個需用mq。訂單系統建立訂單後,發訊息給購物車模組,將已下單商品從購物車刪除。從購物車刪除已...

RabbitMQ訊息佇列的使用

我們知道rabbitmq的exchange常用交換器型別分為fanout direct topic headers 4種型別,這裡我們將對fanout direct topic 3種型別以實際 的形式進行講解,至於關於交換器對各型別的具體講解,請參照文章開始給出的鏈結進行了解,這裡就不再贅述,我們新...