消息隊列是Linux提供的另一個進程通信方法费尽,它源自System V,所以跟典型的用read/write的那些機制長得不一樣尤误。
消息隊列相關系統(tǒng)調用的手冊
mstget(2) msgsnd(2) msgrcv(2) msgctl(2)
消息隊列和管道很相似惹资,也是類似于創(chuàng)建、收發(fā)毛萌、關閉這樣的過程苟弛。
下面代碼模擬了兩個用消息隊列通信的進程。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
struct msg_st{
long mtype;
char mtext[BUFSIZ];
};
int main(int argc, char **argv){
key_t key = ftok(".", 0);
int pid = fork();
if (pid > 0){
//父進程扮演[發(fā)]消息的角色
int id = msgget(key, 0777 | IPC_CREAT);
if (id < 0){
printf("error@%d, %s\n", __LINE__, strerror(errno));
}
if (id >= 0){
struct msg_st data = {1, "hello world!"};
sleep(1);//故意推遲發(fā)送阁将,以便看到接收端的阻塞
printf("before\tsend\n");
if (msgsnd(id, (void*)&data, sizeof("hello world!"), 0) < 0){
printf("error@%d, %s\n", __LINE__, strerror(errno));
}
printf("after \tsend\n");
}
waitpid(pid,NULL,0);
}
else if (pid == 0){
//子進程扮演[收]消息的角色
struct msg_st data;
int id = msgget(key, 0777 | IPC_CREAT);
int n;
if(id < 0){
printf("error@%d, %s\n", __LINE__, strerror(errno));
exit(-1);
}
printf("before\treceive\n");
if ((n = msgrcv(id, (void*)&data, BUFSIZ, 0, 0)) <= 0){
printf("error@%d, %s\n", __LINE__, strerror(errno));
exit(-1);
}
printf("after \treceive\n");
printf("receive: type=%ld, text=[%s]\n", data.mtype, data.mtext);
if (msgctl(id, IPC_RMID, 0) < 0){
printf("error@%d, %s\n", __LINE__, strerror(errno));
exit(-1);
}
printf("delete message queue.\n");
exit(0);
}
return 0;
}
編譯和輸出
#gcc test.c -o test && ./test
before receive
before send
after send
after receive
receive: type=1, text=[hello world!]
delete message queue.
從打印的順序可以看出膏秫,接收是阻塞的。其實發(fā)送也是阻塞的做盅,但要在消息隊列滿的時候才會發(fā)生缤削。關于阻塞行為窘哈,可以用IPC_NOWAIT
這個flag控制。
補充
- 隊列多少是多呢亭敢?消息能有多長滚婉?
宏 | 意義 |
---|---|
MSGMNI |
系統(tǒng)最大消息隊列數(shù) |
MSGMNB |
單個消息隊列最大字節(jié)數(shù) |
MSGMAX |
單個消息最大字節(jié)數(shù) |
- 消息隊列與管道相比有什么不同
消息隊列的收發(fā)更靈活,一個消息隊列就可以分頻道吨拗,收發(fā)都可以選頻道满哪,struct msg_st的mtype成員可以當做這個頻道。
消息隊列還有什么有趣的用途劝篷?