无法正确使用消息队列。

huangapple go评论117阅读模式
英文:

Can't use mqueue properly

问题

我正在尝试理解如何使用`mqueue.h`在工作线程之间进行通信。我知道`mqueue.h`是为进程通信而设计的,而不是线程通信,但这是我能找到的唯一的POSIX队列API,因为我不能使用外部库。

我编写了这个测试代码,但出于某种原因,接收到的值与发送的值不同。这段代码的目的是向另一个线程发送指针。

```c
#include <stdio.h>
#include <errno.h>
#include <mqueue.h>
#include <pthread.h>
#include <fcntl.h>

typedef struct {
    mqd_t id;
    char* name;
} thread_data;

struct mq_attr attr = {0, 10, sizeof(char*), 0};

void *new_thread(void *arg) {
    char* pArg;
    thread_data *pData;
    int res;

    printf("等待接收消息(队列 %d)...\n", *(mqd_t*)arg);
    fflush(stdout);
    res = mq_receive(*(mqd_t*)arg, pArg, sizeof(char*), NULL);

    if (res != -1)
    {
        pData = (thread_data*)pArg;
        printf("在 %p 接收到消息:%s\n", pData, pData->name);
    }
    else
    {
        printf("失败!错误码 = %d\n", errno);
    }
}

int main(int argc, char *argv[])
{
    pthread_t t1;
    thread_data data;

    data.name = "/thread1";
    data.id = mq_open(data.name, O_RDWR | O_CREAT, 0600, &attr);

    printf("发送消息 %p(大小 %ld 字节)\n", &data, sizeof(char*));
    mq_send(data.id, (char*)&data, sizeof(char*), 0);
    printf("消息已发送(队列 %d)。\n", data.id);

    pthread_create(&t1, NULL, new_thread, &data.id);
    pthread_join(t1, NULL);

    return 0;
}

输出看起来类似于这样:

$ ./a.out
发送消息 0x7ffd1c63eb20(大小 8 字节)
消息已发送(队列 3)。
等待接收消息(队列 3)...
在 0x7f5a92279700 接收到消息:

希望有人能解释为什么会发生这种情况,因为我已经花了相当多的时间在这上面。


<details>
<summary>英文:</summary>

I am trying to understand how to use `mqueue.h` to communicate between threads for work. I am aware that `mqueue.h` was designed for process communication and not threads, but it is the only posix queue API I could find, since I cannot use external libraries.

I have written this test code but, for some reason, the value received is different than the value sent. The purpose of this code is to send a pointer to another thread.

```c
#include &lt;stdio.h&gt;
#include &lt;errno.h&gt;
#include &lt;mqueue.h&gt;
#include &lt;pthread.h&gt;
#include &lt;fcntl.h&gt;

typedef struct {
    mqd_t id;
    char* name;
} thread_data;

struct mq_attr attr = {0, 10, sizeof(char*), 0};

void *new_thread(void *arg) {
    char* pArg;
    thread_data *pData;
    int res;

    printf(&quot;Waiting to receive message (queue %d)...\n&quot;, *(mqd_t*)arg);
    fflush(stdout);
    res = mq_receive(*(mqd_t*)arg, pArg, sizeof(char*), NULL);

    if (res != -1)
    {
        pData = (thread_data*)pArg;
        printf(&quot;Message received in %p: %s\n&quot;, pData, pData-&gt;name);
    }
    else
    {
        printf(&quot;Failed! errno = %d\n&quot;, errno);
    }
}

int main(int argc, char *argv[])
{
    pthread_t t1;
    thread_data data;

    data.name = &quot;/thread1&quot;;
    data.id = mq_open(data.name, O_RDWR | O_CREAT, 0600, &amp;attr);

    printf(&quot;Sending message %p (size %ld bytes)\n&quot;, &amp;data, sizeof(char*));
    mq_send(data.id, (char*)&amp;data, sizeof(char*), 0);
    printf(&quot;Message sent (queue %d).\n&quot;, data.id);

    pthread_create(&amp;t1, NULL, new_thread, &amp;data.id);
    pthread_join(t1, NULL);

    return 0;
}

The output looks something like this:

$ ./a.out
Sending message 0x7ffd1c63eb20 (size 8 bytes)
Message sent (queue 3).
Waiting to receive message (queue 3)...
Message received in 0x7f5a92279700:

I'm hoping someone here can explain why this is happening, as I've spent quite some time on this.

答案1

得分: 1

您的代码中存在错误的间接级别。在发送和接收部分都有问题。

您的mq_send()调用发送了指向要发送的结构的内容的前8个字节。而您的mq_receive()调用尝试将数据存储在一个未初始化的指针中。

要修复发送部分:

    thread_data data;
    thread_data* ptr = &amp;data;

    /* ... 代码 ... */
    mq_send(data.id, (char*)&amp;ptr, sizeof(thread_data*), 0);
    /* ... 其他代码 ... */

注意这里的 &amp;ptr - 您试图发送值 ptr(它本身是一个指针,但这在这里不重要),这意味着您必须传递指向该值的指针给 mq_send

在接收部分,您需要进行以下更改:

    /* 删除 pArg 部分 */
    res = mq_receive(*(mqd_t*)arg, (char*)&amp;pData, sizeof(thread_data*), NULL);
    if (res == sizeof(thread_data*)) {
        /* 打印 pData-> ... */
    } else {
        /* 错误处理 */
    }

再次强调,您想要接收值 pData,所以您必须将指向该值的指针传递给 mq_receive。不要直接指定指针,这意味着访问未初始化的内存。

为了使这更清晰,假设您想要发送一个整数,那么您需要以下代码:

/* 另外初始化队列为 sizeof(int) */
int x = 42;
mq_send(data.id, (char*)&amp;x, sizeof(int), 0);
/* 接收部分 */
int y = 0;
res = mq_receive(*(mqd_t*)arg, (char*)&amp;y, sizeof(int), NULL);

因为您想要发送指针而不是整数,所以在mq函数中更改变量的类型和大小 - 但在这两种情况下,都需要将 (char*)&amp;variable 传递给mq方法。无论变量保存的是整数还是指针,都是一样的。

英文:

You don't have the correct level of indirection in your code, both in the send as well as the receive part.

Your mq_send() call sends the first 8 bytes of the contents of the structure whose pointer you are trying to send. Your mq_receive() call tries to store the data in an uninitialized pointer.

To fix the send part:

    thread_data data;
    thread_data* ptr = &amp;data;

    /* ... code ... */
    mq_send(data.id, (char*)&amp;ptr, sizeof(thread_data*), 0);
    /* ... other code ... */

Note the &amp;ptr here -- you are trying to send the value ptr (which itself is a pointer, but that's immaterial here), which means that you have to pass a pointer to that value to mq_send.

In the receive part, you'll have to change it as follows:

    /* drop the pArg stuff */
    res = mq_receive(*(mqd_t*)arg, (char*)&amp;pData, sizeof(thread_data*), NULL);
    if (res == sizeof(thread_data*)) {
        /* print pData-&gt; ... */
    } else {
        /* error handling */
    }

Again, you want to receive the value pData here, so you have to pass a pointer to that value to mq_receive. Don't specify the pointer directly, that just means access to uninitialized memory.

To make this a bit clearer, let's say you wanted to send an integer, then you'd need the following code:

/* plus initialize the queue with sizeof(int) */
int x = 42;
mq_send(data.id, (char*)&amp;x, sizeof(int), 0);
/* and in the receive part */
int y = 0;
res = mq_receive(*(mqd_t*)arg, (char*)&amp;y, sizeof(int), NULL);

Since you want to send a pointer instead of an integer, the change is in the type of the variable and the size passed to the mq functions - but in both cases you do pass (char*)&amp;variable to the mq methods. Whether the variable holds an integer or a pointer is immaterial.

huangapple
  • 本文由 发表于 2023年3月7日 06:58:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75656588.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定