System V 消息隊列使用消息隊列標識符(Message Queue Identifier)。具有足夠特權的任何進程都可以往一個給定進程放置一個消息。也可以讀出一個消息。跟Posix消息隊列一樣,在寫消息之前,不求另外某個進程正在等待該隊列上一個消息的到達。
對於每個消息隊列,內核維護一個定義在<sys/msg.h>頭文件中的信息結構。
struct msqid_ds {
struct ipc_perm msg_perm; /* read_write perms */
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
time_t msg_stime; /* last msgsnd time */
time_t msg_rtime; /* last msgrcv time */
time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
msglen_t msg_cbytes; /* current number of bytes on queue */
msgqnum_t msg_qnum; /* number of messages in queue */
msglen_t msg_qbytes; /* max number of bytes on queue */
pid_t msg_lspid; /* pid of last msgsnd */
pid_t msg_lrpid; /* last receive pid */
};
msgget
創建一個新的消息隊列或者訪問一個已存在的消息隊列。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
// 返回:若成功則爲非負標識符,出錯爲-1
key:既可以是ftok的返回值,也可以是常值IPC_PRIVATE。
msgflg:讀寫權限位的組合(MSG_R、MSG_W),還可以與 IPC_CREATE、IPC_CREATE | IPC_EXCL 按爲或。
當創建一個新的消息隊列時,msqid_ds結構的如下成員被初始化:
(1)msg_perm結構的uid和cuid成員被設置成當前進程的有效用戶ID,gid和cgid成員被設置成當前進程的有效組ID
(2)msgflg中的讀寫權限位存放在msg_perm.mode中
(3)msg_qnum,msg_lspid,msg_lrpid,msg_stime,msg_rtime被置爲0
(4)msg_ctime被設置成當前時間
(5)msg_qbytes被設置成系統限制值
msgsnd、msgrcv
msgsnd使用msgget打開一個消息隊列後,使用msgsnd往其上放置一個消息。
msgrcv從某個消息隊列中讀出一個消息。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// 返回:若成功則爲0,出錯-1
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
// 返回:若成功則爲讀入緩衝區中的數據的字節數,出錯-1
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
-------------------------------------- msgsnd -----------------------------------------
msqid:由msgget返回的標識符。msgp:結構指針,msgbuf。通常一個字節的數據是不夠用的,可以自定義。
msgflg:可以是0,可以是IPC_NOWAIT(使得msgsnd調用非阻塞nonblocking,如果沒有存放新消息的可用空間,就立馬返回)。
- 在指定的隊列中已有太多的字節;
- 在系統範圍存在太多的消息。
如果這兩個條件有一個存在,而且IPC_NOWAIT已指定,msgsnd就返回一個EAGAIN錯誤。如果有一個存在,且未指定IPC_NOWAIT標誌,那麼調用線程被投入睡眠,直到:
- 具備存放新消息的空間;
- 由msqid標識的消息隊列從系統中刪除(返回EIDRM錯誤);
- 調用線程被某個信號所中斷(返回EINTR錯誤。)
------------------------------------ msgrcv -----------------------------------------------
msgtyp:指定希望讀出什麼樣的消息。
- type == 0: 表示將會返回隊列中的第一個消息。
- type > 0 : 表示將會返回隊列中消息類型的值等於type參數的第一個消息。
- type < 0 : 表示將會返回隊列中小於或者等於type的絕對值中最小的第一個消息。
msgflg指定所請求的消息不在隊列時的處理。在沒有消息可得的情況下,如果設置了IPC_NOWAIT位,立即返回一個ENOMSG錯誤,否則阻塞到下列某個事件發生爲止
(1)有一個所請求類型的消息可獲取
(2)由msqid標識的消息隊列被從系統中刪除
(3)調用線程被某個捕獲的信號所中斷
msgflg參數中另有一位可以指定MSG_NOERROR,當所接收消息的真正數據部分大於length參數時,如果設置了該位,msgrcv函數只是截短數據部分,而不返回錯誤,否則,返回一個E2BIG錯誤。
msgctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
// 返回:若成功則爲0,出錯-1
msgctl提供在一個消息隊列上的各種控制操作。
有三個命令:
(1)IPC_RMID: 從系統中刪除msqid指定的消息隊列。當前在該隊列上的任何消息都被丟棄
(2)IPC_SET : 給隊列設置其中的msqid_ds結構的四個成員:msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes
(3)IPC_STAT: 給調用者返回指定隊列的當前msqid_ds結構
複用消息
與一個隊列中的每個消息相關聯的類型字段提供了兩個特性:
(1)類型字段可以用於標識消息,從而允許多個進程在單個隊列上複用消息。
(2)類型字段可以用做優先級,允許接收者以不同於先進先出的某個順序讀出各個消息。
限制