我想知道消息队列在Linux内核中是如何实现的。
答案1
Linux内核(2.6)实现了两个消息队列:(
而不是“消息列表”,因为实现是使用链表完成的,不严格遵循先进先出原则)
系统V IPC消息
来自 System V 的消息队列。
进程可以调用msgsnd()
来发送消息。他需要传递接收消息队列的IPC标识符、消息的大小和消息结构,包括消息类型和文本。
另一方面,进程调用msgrcv()
接收消息,传递消息队列的 IPC 标识符、消息应存储的位置、大小和值t。
t指定从队列返回的消息,正值表示第一条消息,其类型等于t返回,负值返回等于类型的最后一条消息t零返回队列的第一条消息。
这些函数定义在包括/linux/msg.h并实施于ipc/msg.c
消息大小 (max)、消息总数 (mni) 和队列中所有消息的总大小 (mnb) 均受到限制:
$ sysctl kernel.msg{max,mni,mnb}
kernel.msgmax = 8192
kernel.msgmni = 1655
kernel.msgmnb = 16384
上面的输出来自 Ubuntu 10.10 系统,默认值定义在消息.h。
更令人难以置信的旧 System V 消息队列内容解释这里。
POSIX 消息队列
POSIX标准定义了基于System V IPC消息队列的消息队列机制,并扩展了一些功能:
- 简单的基于文件的应用程序界面
- 支持消息优先级
- 支持异步通知
- 阻塞操作超时
例子
util-linux
提供了一些用于分析和修改消息队列的程序,POSIX规范给出了一些C示例:
ipcmk
使用;创建消息队列通常,您可以通过调用 C 函数(例如ftok()
and )来完成此操作msgget()
:
$ ipcmk -Q
让我们看看使用ipcs
or发生了什么cat /proc/sysvipc/msg
:
$ ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x33ec1686 65536 user 644 0 0
现在用一些消息填充队列:
$ cat <<EOF >msg_send.c
#include <string.h>
#include <sys/msg.h>
int main() {
int msqid = 65536;
struct message {
long type;
char text[20];
} msg;
msg.type = 1;
strcpy(msg.text, "This is message 1");
msgsnd(msqid, (void *) &msg, sizeof(msg.text), IPC_NOWAIT);
strcpy(msg.text, "This is message 2");
msgsnd(msqid, (void *) &msg, sizeof(msg.text), IPC_NOWAIT);
return 0;
}
EOF
同样,您通常不会在代码中对 msqid 进行硬编码。
$ gcc -o msg_send msg_send.c
$ ./msg_send
$ ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x33ec1686 65536 user 644 40 2
另一边将接收消息:
$ cat <<EOF >msg_recv.c
#include <stdio.h>
#include <sys/msg.h>
int main() {
int msqid = 65536;
struct message {
long type;
char text[20];
} msg;
long msgtyp = 0;
msgrcv(msqid, (void *) &msg, sizeof(msg.text), msgtyp, MSG_NOERROR | IPC_NOWAIT);
printf("%s \n", msg.text);
return 0;
}
EOF
走着瞧吧:
$ gcc -o msg_recv msg_recv.c
$ ./msg_recv
This is message 1
$ ./msg_recv
This is message 2
$ ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0x33ec1686 65536 user 644 0 0
两次接收后,队列再次为空。
之后通过指定键 ( -Q
) 或 msqid ( -q
) 将其删除:
$ ipcrm -q 65536