【问题标题】:Can't use shm_open after receiving from message queue从消息队列接收后无法使用 shm_open
【发布时间】:2019-09-05 07:59:22
【问题描述】:

我正在尝试使用以下步骤在同一代码中实现多个 IPC 方法:

  • 1 - Process1 打开一个消息队列并读取从 Process2 发送的消息

  • 2 - Process1 关闭并取消链接消息队列

  • 3 - Process1 将某些内容写入共享内存。

在第 3 步,任何 shm_open()memset()memcpy() 系统调用都会失败,并且 Eclipse 会挂在一个新窗口中,显示“在 *** 找不到源文件”对于我调用的任何函数。

当我禁用队列接收操作并仅执行共享内存时,一切正常。

所以我怀疑队列中发生了一些未完成的事务,阻止了来自进程的任何进一步调用

这是代码中的问题:(只是添加了相关部分)

...

static int receiveFromQ(char *msgQName)
{
    int msgQFD;
    char buffer[33];

    /* Create and open the communication message queue */
    msgQFD = mq_open(msgQName, O_RDONLY | O_CREAT, 0660, NULL);

    /* Read the message from the queue and store it in the reception buffer */
    memset(buffer, 0, sizeof(buffer));
    mq_receive(msgQFD, buffer, sizeof(buffer), NULL); // This is a blocking point until a message is received

    /* Use the data received ... */

    /* Close the queue */
    mq_close(msgQFD);

    /* Remove the message queue */
    mq_unlink(msgQName);

    return 1;
}

int main(void)
{
       char *key = SM_KEY;
       int shmFD;

    /* Receive the data from the queue */
    int ret = receiveFromQ(MSGQ_NAME);

       /* Creates a shared memory object in a kernel space, with size = 0 */
    shmFD = shm_open(key, O_CREAT | O_RDWR | O_TRUNC, 0660); //The software stops here!
...
}

软件没有创建共享内存,而是挂在shm_open() 并声称找不到shm_open 的源。

【问题讨论】:

  • 问题描述似乎不一致。 shm_open() 是否调用hang,还是失败了?只有在后一种情况下,才有理由说它“声称找不到 shm_open 的来源”。此外,您如何确定执行甚至到达shm_open() 调用?
  • 总的来说,您必须确保检查所有方法调用的返回码,以捕获失败代码并做出适当反应。这将使您更好地了解正在发生的事情。但是,为了让我们更直接地帮助您,我们可能需要一个重现问题的minimal reproducible example,其中可能包含其他参与计划的代码。
  • 当我调试程序时,它在 shm_open 失败并将我引导到“找不到源”窗口。如果在调用 receiveFromQ() 之前调用 shm_open 函数,则可以正常工作。
  • 我猜测您正在破坏/*use the data received */ 中的堆栈,因此shm_open 现在采用key 的值,即垃圾。您显示的代码不会触发它。
  • 它正在停止,因为在调用shm_open 时发生了某事。找到停止的原因很重要。这可能是 key 变量中的值的 SEGV(地址无效错误)。缺少源代码只是因为它在 C 运行时中,您没有源代码。在调用shm_open 之前放置一个断点并验证key 变量是否正常。 (或者,在key 变量的地址上放置一个写断点,然后查看它何时触发。)

标签: c linux ipc message-queue shared-memory


【解决方案1】:
memset(buffer, 0, sizeof(buffer));

这将设置buffer[0] = 0,因为sizeof(buffer) = sizeof(char*) = 1。 更好的主意是:

char buffer[33] = {0};

或者

#define BUFFER_LEN 33U
...
char buffer[BUFFER_LEN];
...
memset(buffer, 0, sizeof(char) * BUFFER_LEN);

或者

memset(buffer, 0, sizeof(buffer) / sizeof(buffer[0]);

sizeof(buffer) / sizeof(buffer[0] 计算固定数组的大小(非指针使用 malloc 分配)。所以结果将是 33。

【讨论】:

  • 这不是真的。对于char buffer[33],则sizeof(buffer)sizeof(char[33])sizeof(char) * 3333。将数组类型隐式转换为类型指针的少数例外之一是在 sizeof 表达式内。
  • 我确信有一些时髦的嵌入式 DSP 或类似的架构,其中指针的大小为 1。OP 没有使用它。并且缓冲区数组的大小与指向char的指针的大小不同。
  • 你好像很困惑伊戈尔。 sizeof(buffer) 是变量缓冲区的大小。缓冲区变量是一个包含 33 个chars 的数组。所以sizoef(buffer) 的大小是 33 chars。数组(在大多数情况下)在 C 语言中被隐式转换为指针(这对新程序员来说是最令人困惑的)。例如sizeof(buffer + 1)sizeof(char*)+ 1 使 buffer 隐式转换为指向 char 的指针。转换后+ 1不执行,编译器只需要类型解析。
  • sizeof(buffer) / sizeof(buffer[0]) 是数组中计数的常用助记符。 buffer 的类型是 char[33],所以 sizeof(buffer)33 * sizeof(char)buffer[0] 的类型是char,它是一个char。所以sizeof(buffer) / sizeof(buffer[0]) 等于sizeof(char[33]) / sizeof(char) 等于33 * sizeof(char) / sizeof(char)。碰巧sizeof(char) 等于 1,这是由标准保证的。使用memset(buffer, 0, sizeof(char) * BUFFER_LEN);memset(buffer, 0, sizeof(buffer)memset(buffer, 0, sizeof(char[33])) 相同
  • 我相信这不是问题,因为该函数工作正常并且可以正确读取接收到的值。
【解决方案2】:

正如@Petesh 所提到的,问题出在 /* 使用接收到的数据 */ 部分我从代码中省略了,因为我认为它无关紧要!澄清一下:在这一部分中,我在使用 memcpy() 复制的数据大小上犯了一个错误,导致缓冲区溢出。这没有显示任何错误,但以某种方式阻止了程序的进一步处理。 谢谢大家提供有用的cmets。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    • 2012-11-16
    • 2010-09-19
    • 2011-07-10
    • 2011-07-08
    • 2012-01-19
    • 1970-01-01
    相关资源
    最近更新 更多