英文:
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 <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("Waiting to receive message (queue %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("Message received in %p: %s\n", pData, pData->name);
}
else
{
printf("Failed! errno = %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("Sending message %p (size %ld bytes)\n", &data, sizeof(char*));
mq_send(data.id, (char*)&data, sizeof(char*), 0);
printf("Message sent (queue %d).\n", data.id);
pthread_create(&t1, NULL, new_thread, &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 = &data;
/* ... 代码 ... */
mq_send(data.id, (char*)&ptr, sizeof(thread_data*), 0);
/* ... 其他代码 ... */
注意这里的 &ptr
- 您试图发送值 ptr
(它本身是一个指针,但这在这里不重要),这意味着您必须传递指向该值的指针给 mq_send
。
在接收部分,您需要进行以下更改:
/* 删除 pArg 部分 */
res = mq_receive(*(mqd_t*)arg, (char*)&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*)&x, sizeof(int), 0);
/* 接收部分 */
int y = 0;
res = mq_receive(*(mqd_t*)arg, (char*)&y, sizeof(int), NULL);
因为您想要发送指针而不是整数,所以在mq函数中更改变量的类型和大小 - 但在这两种情况下,都需要将 (char*)&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 = &data;
/* ... code ... */
mq_send(data.id, (char*)&ptr, sizeof(thread_data*), 0);
/* ... other code ... */
Note the &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*)&pData, sizeof(thread_data*), NULL);
if (res == sizeof(thread_data*)) {
/* print pData-> ... */
} 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*)&x, sizeof(int), 0);
/* and in the receive part */
int y = 0;
res = mq_receive(*(mqd_t*)arg, (char*)&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*)&variable
to the mq methods. Whether the variable holds an integer or a pointer is immaterial.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论