3.消息队列
消息队列和命名管道有很多相似之处,但少了打开和关闭管道方面的复杂性。消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。而且,每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型值得数据块。
优点:通过发消息几乎完全避免命名管道得同步和阻塞问题,而且可以提前查看紧急消息。
缺点:和管道一样,每个数据块都有一个最大长度得限制,系统中所有队列所包含得全部数据块得总长度也有一个上限。
消息队列函数的定义:
#include
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgget(key_t key, int msgflg);
int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);
(1) msgget函数
int msgget(key_t key, int msgflg);
第一个参数位程序提供的键值,用来命名某个特定的消息队列。
第二个参数msgflg有9个权限标志组成。
(2)msgsnd函数
int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);
第一个参数msqid是消息队列标识符
第二个参数msg_ptr是一个指向准备发送消息的指针。
第三个参数msg_sz是msg_ptr指向的消息的长度。
第四个参数msgflg控制在当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。
这个函数成功时返回0,失败返回-1。如果调用成功,消息数据的一份副本将被放到消息队列中。
(3)msgrcv函数
int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
第一个参数:标识符
第二个参数:指向准备接收消息的指针。
第三个参数:消息的长度。
第四个参数:接收消息的优先级。
第五个参数:用于控制当队列中没有相应类型的消息可以接收时将发生的事情。
(4)msgctl函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
控制函数
第一个参数:msqid是标识符
第二个参数:command是将要采取的动作。
用个实例说明一下消息队列的实现
接收者程序:msg1.c
#include#include #include #include #include #include struct my_msg_st { long int my_msg_type; char some_text[BUFSIZ]; }; int main() { int running = 1; int msgid; struct my_msg_st some_data; long int msg_to_receive = 0; msgid = msgget((key_t)1234, 0666 | IPC_CREAT); if (msgid == -1) { fprintf(stderr, "msgget failed with error: %dn", errno); exit(EXIT_FAILURE); } while(running) { if (msgrcv(msgid, (void *)&some_data, BUFSIZ, msg_to_receive, 0) == -1) { fprintf(stderr, "msgrcv failed with error: %dn", errno); exit(EXIT_FAILURE); } printf("You wrote: %s", some_data.some_text); if (strncmp(some_data.some_text, "end", 3) == 0) { running = 0; } } if (msgctl(msgid, IPC_RMID, 0) == -1) { fprintf(stderr, "msgctl(IPC_RMID) failedn"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
发送者程序:msg2.c
#include#include #include #include #include #include #define MAX_TEXT 512 struct my_msg_st { long int my_msg_type; char some_text[MAX_TEXT]; }; int main() { int running = 1; struct my_msg_st some_data; int msgid; char buffer[BUFSIZ]; msgid = msgget((key_t)1234, 0666 | IPC_CREAT); if (msgid == -1) { fprintf(stderr, "msgget failed with error: %dn", errno); exit(EXIT_FAILURE); } while(running) { printf("Enter some text: "); fgets(buffer, BUFSIZ, stdin); some_data.my_msg_type = 1; strcpy(some_data.some_text, buffer); if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) { fprintf(stderr, "msgsnd failedn"); exit(EXIT_FAILURE); } if (strncmp(buffer, "end", 3) == 0) { running = 0; } } exit(EXIT_SUCCESS); }
输出结果:
解析:发送者程序通过msgget来创建一个消息队列,然后用msgsnd向队列中增加消息。接收者用msgget获得消息队列标志符,然后开始接收消息,直到收到特殊的文本end为止。然后它用msgctl来删除消息队列以完成清理工作。
关于消息队列,我们完全可以DIY,封装接口来实现一个更复杂的消息队列,用双向循环链表的数据结构来串联消息,便于定义消息处理顺序的规则,并且便于插入和删除消息;把结构体my_msg_st设计更多自己想要的成员,比如消息类型,消息处理方式,是否为紧急消息(紧急消息调度优先级高,可提前处理)等,细节这里就不深入讲了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)