不同的Linux消息队列有相同的ID?

4

我在一个 .c 文件中打开了一个消息队列,成功后它会显示消息队列 ID 为 3。当该程序仍在运行时,在另一个终端中启动另一个程序(另一个 .c 文件),它会创建一个具有不同 mqd_t 的新消息队列。但它的 ID 也显示为 3。这是个问题吗?

服务器文件如下:

void server(char* req_mq) {
struct mq_attr attr;
mqd_t mqdes;
struct request* msgptr;

int n;
char *bufptr;
int buflen;
pid_t apid;

//attr.mq_maxmsg = 300;
//attr.mq_msgsize = 1024;

mqdes = mq_open(req_mq, O_RDWR | O_CREAT, 0666, NULL);
if (mqdes == -1) {
    perror("can not create msg queue\n");
    exit(1);
}
printf("server mq created, mq id = %d\n", (int) mqdes);

客户端的表现如下:

void client(char* req_mq, int min, int max, char* dir_path_name, char* outfile) {

pid_t pid;

/* get the process id */
if ((pid = getpid()) < 0) {
    perror("unable to get client pid");
}

mqd_t mqd, dq;

char pfx[50] = DQ_PRFX;
char suffix[50]; //
sprintf(suffix, "%d", pid);
strcat(pfx, suffix);

dq = mq_open(pfx, O_RDWR | O_CREAT, 0666, NULL);
if (dq == -1) {
    perror("can not open data queue\n");
    exit(1);
}
printf("data queue created, mq id = %d\n", (int) dq);

mqd = mq_open(req_mq, O_RDWR);
if (mqd == -1) {
    perror("can not open msg queue\n");
    exit(1);
}
和似乎共享相同的ID 3。

是的,我同意你的看法。但是这样难道不应该将id=3分配给服务器的mq,将id=4分配给客户端的mq吗? - Halo
2
@Haio - 从技术上讲,你不应该关心mq_id,除了检查它是否有效并在需要时使用它。 mqd_t是故意不透明的,你不应该假设它将是一个int,并且在引用时应将其转换为mqd_t。 - Duck
@Duck - mqd_t 是一个整数类型的东西,正如 POSIX、Linux 和 FreeBSD 的 mq_open(3) 手册所建议的那样。也就是说,它们都表示该函数在出错时应返回 (mqd_t)-1。实际上,在 Linux 中它是一个文件描述符,即一个 int - FooF
@FooF,posix有一个专门介绍其要求语言精度的部分。虽然你通常可以直觉地了解类型的实现(或者通过sys/types.h等追溯),但将其设置为不透明的主要目的是它可能会发生变化,从而导致做出假设的程序出现问题。没有什么可以阻止mqd_t被实现为联合或其他任何形式。我知道人们可以并且确实会做出假设。但有时候会产生长期后果和平台特定的意外结果。 - Duck
我认为你表达的主要观点是我们不应该关心mqd_t,我完全同意。我只是想表达技术上的观察,即它并不那么难懂。我不认为你可以将“-1”转换为联合(或结构)类型!?!如果mqd_t是不透明的,那么就需要一个特殊的常量来表示错误。我的评论只涉及“opaque”这个词的语义。该类型类似于pid_tfork(2)可能会返回(pid_t)-1表示错误)。它不像pthread_t,后者是不透明类型,在符合POSIX标准的方式下不能具有值“-1”。 - FooF
3个回答

3
将句柄视为数组索引。它是操作系统中的一个数组索引,每个进程都有一个。
当您打开句柄(无论是文件、消息队列、套接字等),操作系统会在一个唯一的数组中记录该对象的设置,该数组仅适用于您的进程。然后,操作系统将返回一个索引到该数组中的程序。
每次您的程序使用该“句柄”时,操作系统实际上只是查找该私有数组中的结构,以了解如何处理与该“句柄”相关联的对象。
Linux通常将句柄0、1和2分别保留为STDIN、STDOUT和STDERR。但从那时起,您打开的任何句柄都将编号为3、4等。您的句柄3可能与文件“/tmp/foo.txt”相关,而另一个进程的句柄3可能与文件“/tmp/bar.txt”相关。因此,如果两个进程正在使用类似的文件“句柄”,则无关紧要。
顺便说一下,您不需要知道或关心句柄实际包含什么。理论上,它可以是任何东西 - 魔术数字、指针、整数,都无所谓。句柄实际上是一个秘密令牌,您只需在需要访问系统对象时将其交给操作系统即可。

或许在理念构思和实际实现的差异之间再加强一点强调会更好。 - Duck

0

可能是你没有关闭第一个消息队列。因为在这种情况下,操作系统会给新的消息队列分配相同的ID(索引)。


消息队列描述符是进程范围的句柄。一个进程对于打开的消息队列所拥有的值与其他进程完全无关。消息队列的名称才是重要的,这是不同进程找到相同消息队列的方式。 - FooF

0

消息队列的特殊之处在于,您使用mq_open(3)打开消息队列时给它们命名。由mq_open(3)返回的消息队列描述符仅在进程范围内有意义,换句话说,另一个进程对于消息队列描述符的值是完全无关紧要的。这与文件路径和文件描述符完全相似。事实上,Linux中的消息队列描述符实际上就是文件描述符-请参见Linux手册mq_overview(7)。这就是为什么当两个进程打开消息队列时,您会看到常见值3的原因(在最典型的情况下, 0、1、2已经为提供STDINSTDOUTSTDERR而被打开,如 PP.的答案所述)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接