消息隊列是 Linux 核心中維護的消息鏈表,透過唯一的隊列標識符進行管理,實現了進程或線程之間的異步通信機制。它允許發送者將消息放入隊列,接收者則在稍後從隊列中讀取,雙方無需同步等待,極大地提升了並發程式的靈活性與解耦能力。
long 類型的 mtype(消息類型)與資料緩衝區。#include <sys/msg.h>
int msgget(key_t key, int flag);
// 成功返回消息隊列 ID;失敗返回 -1
key 通常由 ftok() 產生,flag 常用 IPC_CREAT | 0666 表示建立並設定權限。
#include <sys/msg.h>
int msgsnd(int msgid, const void *ptr, size_t nbytes, int flag);
// 成功返回 0;失敗返回 -1
flag 選項決定阻塞行為:
IPC_NOWAIT:隊列已滿時立即返回 EAGAIN 錯誤,不阻塞。ssize_t msgrcv(int msgid, void *ptr, size_t nbytes, long type, int flag);
type 參數控制讀取策略:
type == 0:讀取隊列第一條消息(FIFO)。type > 0:讀取類型值等於 type 的第一條消息。type < 0:讀取類型值 ≤ |type| 的消息;若有多條符合,取類型值最小者。#define MSG_FILE "."
#define BUFFER 255
struct msgtype {
long mtype;
char buffer[BUFFER + 1];
};
key_t key;
int msgid;
struct msgtype msg;
/* 1. 產生鍵值 */
if ((key = ftok(MSG_FILE, 'a')) == -1) {
perror("ftok");
exit(1);
}
/* 2. 建立/開啟隊列 */
if ((msgid = msgget(key, IPC_CREAT | 0666)) == -1) {
perror("msgget");
exit(1);
}
/* 3. 發送消息 */
msg.mtype = 1;
strncpy(msg.buffer, "Hello Queue", BUFFER);
msgsnd(msgid, &msg, sizeof(msg.buffer), 0);
/* 4. 接收消息 */
msgrcv(msgid, &msg, sizeof(msg.buffer), 1, 0);
printf("Received: %s\n", msg.buffer);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <pthread.h>
#define MSG_FILE "."
#define BUFFER 255
#define PERM (S_IRUSR | S_IWUSR)
struct msgtype {
long mtype;
char buffer[BUFFER + 1];
};
void *thr_test(void *arg) {
struct msgtype msg;
int msgid = *((int *)arg);
printf("Thread: msgid=%d\n", msgid);
/* 接收類型 1 的消息 */
msgrcv(msgid, &msg, sizeof(msg.buffer), 1, 0);
fprintf(stderr, "Server Received: %s\n", msg.buffer);
/* 回覆類型 2 的消息 */
msg.mtype = 2;
strcpy(msg.buffer, "ACK from thread");
msgsnd(msgid, &msg, sizeof(msg.buffer), 0);
pthread_exit((void *)2);
}
int main(int argc, char **argv) {
struct msgtype msg;
key_t key;
int msgid;
pthread_t tid;
if (argc != 2) {
fprintf(stderr, "Usage: %s \n", argv[0]);
exit(1);
}
if ((key = ftok(MSG_FILE, 'a')) == -1) {
perror("ftok");
exit(1);
}
if ((msgid = msgget(key, IPC_CREAT | 0666)) == -1) {
perror("msgget");
exit(1);
}
fprintf(stderr, "Message Queue ID: %d\n", msgid);
pthread_create(&tid, NULL, thr_test, &msgid);
/* 主線程發送類型 1 */
msg.mtype = 1;
strncpy(msg.buffer, argv[1], BUFFER);
msgsnd(msgid, &msg, sizeof(msg.buffer), 0);
/* 等待線程結束 */
pthread_join(tid, NULL);
return 0;
}
透過上述範例可見,消息隊列配合 mtype 欄位,能輕易實現多線程間的請求-回應模式,是 Linux 進程間通信(IPC)的經典利器。