消息隊列是 System V IPC 機制的一種,提供 內核持久化的訊息緩衝區。特點:
int msgget(key_t key, int msgflg);
| 參數 | 說明 |
|---|---|
| key | IPC 鍵值 (ftok 產生或 IPC_PRIVATE) |
| msgflg | 權限 | IPC_CREAT | IPC_EXCL 等標誌 |
返回:隊列標識符 (msqid),失敗返 -1
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
訊息結構要求:第一成員 必須是 long 類型 (mtype),用於類型過濾
struct my_msg {
long mtype; // 訊息類型 (>0)
char mtext[256]; // 訊息內容
// 可擴展其他欄位
};
| 參數 | 說明 |
|---|---|
| msqid | msgget 返回的隊列 ID |
| msgp | 指向訊息結構體的指標 |
| msgsz | 訊息資料部分大小 (不含 mtype) |
| msgflg | IPC_NOWAIT (非阻塞) 或 0 (阻塞等待) |
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
| msgtyp 值 | 接收行為 |
|---|---|
| 0 | 接收隊列中第一條訊息 (FIFO) |
| >0 | 接收第一條 mtype == msgtyp 的訊息 |
| <0 | 接收第一條 mtype ≤ |msgtyp| 的訊息 (優先級模式) |
返回:實際讀取的資料部分位元組數,失敗返 -1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
| 命令 | 功能 | buf 用途 |
|---|---|---|
| IPC_RMID | 刪除隊列 | 忽略 (可傳 NULL) |
| IPC_STAT | 獲取隊列狀態 | 填充 msqid_ds 結構 |
| IPC_SET | 設置隊列屬性 | 從 msqid_ds 讀取屬性 |
msqid_ds 關鍵成員 (內核定義):
struct msqid_ds {
struct ipc_perm msg_perm; // 權限/擁有者
time_t msg_stime; // 最後 msgsnd 時間
time_t msg_rtime; // 最後 msgrcv 時間
time_t msg_ctime; // 最後變更時間
unsigned long msg_cbytes; // 當前隊列位元組數
unsigned long msg_qnum; // 當前訊息數
unsigned long msg_qbytes; // 隊列最大位元組數
pid_t msg_lspid; // 最後發送者 PID
pid_t msg_lrpid; // 最後接收者 PID
};
// 1. 定義訊息類型
struct msgbuf {
long mtype;
char data[100];
} msg;
// 2. 獲取/建立隊列
int msqid = msgget(111, 0666 | IPC_CREAT);
// 3. 準備數據
msg.mtype = 1; // 類型 1
strcpy(msg.data, \"hello message queue\");
// 4. 發送 (阻塞模式)
msgsnd(msqid, &msg, strlen(msg.data)+1, 0);
printf(\"write data: %s\\n\", msg.data);
// 1. 獲取現有隊列
int msqid = msgget(111, 0666);
// 2. 接收 (類型 0 表示任意)
struct msgbuf msg;
msgrcv(msqid, &msg, sizeof(msg.data), 0, 0);
printf(\"read data: %s\\n\", msg.data);
// 3. 可選:刪除隊列 (通常由最後一個進程清理)
msgctl(msqid, IPC_RMID, NULL);
$ ./msg -w
write data into message.count:3,data:hello message queue
$ ./msg -r
the data of message .count:3,data:hello message queue
sizeof(struct) - sizeof(long),不含 mtype// 定義多種訊息類型
#define MSG_TYPE_URGENT 10 // 高優先級
#define MSG_TYPE_NORMAL 5 // 普通
#define MSG_TYPE_LOW 1 // 低優先級
// 接收端:優先處理緊急訊息
while (1) {
// 先嘗試接收緊急訊息 (非阻塞)
if (msgrcv(msqid, &msg, MSGSZ, MSG_TYPE_URGENT, IPC_NOWAIT) != -1) {
handle_urgent(&msg);
continue;
}
// 再接收普通訊息
if (msgrcv(msqid, &msg, MSGSZ, MSG_TYPE_NORMAL, IPC_NOWAIT) != -1) {
handle_normal(&msg);
continue;
}
// 最後阻塞等待低優先級
msgrcv(msqid, &msg, MSGSZ, MSG_TYPE_LOW, 0);
handle_low(&msg);
}
| 特性 | 消息隊列 | 管道/FIFO | 共享記憶體 |
|---|---|---|---|
| 資料單位 | 訊息 (有邊界) | 位元組流 (無邊界) | 任意結構 |
| 同步機制 | 內建阻塞/非阻塞 | 內建阻塞 | 需外部同步 (信號量) |
| 優先級 | 支援 | 不支援 | 不支援 |
| 持久性 | 內核持久化 | 進程結束即銷毀 | 進程結束即銷毀 |
| 效能 | 中等 (需複製) | 中等 | 最高 (零複製) |