【问题标题】:Linux Shared Memory with C++: Segmentation Fault使用 C++ 的 Linux 共享内存:分段错误
【发布时间】:2018-03-12 08:09:42
【问题描述】:

我正在关注 Linux 编程接口书(第 1004-1005 页)。

我知道这本书使用 C。但我想在 C++ 中实现相同的行为。即:进程间通过共享内存共享一个struct。

#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

using namespace std;

struct my_pair {
  int a;
  int b;
};

int main()
{
  key_t key = ftok("aaaaa", 1);
  int shmid = shmget(key, sizeof(my_pair), IPC_CREAT);
  my_pair *numbers;
  numbers = shmat(shmid, NULL, 0);

  cout << numbers->a;

  return 0;
}

它给了我这个错误:

shteste.cpp:在函数'int main()'中:

shteste.cpp:18: 错误:从 'void*' 到 'my_pair*' 的无效转换

我知道 C++ 更严格。如果我将 shmat 的返回值强制转换为 (my_pair *),它会编译但在执行期间会出现分段错误。

是否可以(如何)在 C++ 中使用 Linux/C 共享内存设施?

我正在编译:G++ 4.4.7:g++ shteste.cpp -o shteste -std=c++0x

谢谢...

编辑:按照所有建议,这是现在的代码:

int main()
{
 key_t key;

 if ((key = ftok("/home/alunos/scd/g11/aaaaa", 1)) == (key_t) -1) {
   perror("IPC error: ftok"); exit(1);
 }

 int shmid = shmget(key , sizeof(my_pair), IPC_CREAT | 0640);

 if (shmid == -1) {
     perror("Could not get shared memory");
     return EXIT_FAILURE;
 }

 my_pair *numbers;
 void* mem = (my_pair*) shmat(shmid, NULL, 0);
 if (mem == reinterpret_cast<void*>(-1)) {
     perror("Could not get shared memory location");
     return EXIT_FAILURE;
 } else {
     numbers = reinterpret_cast<my_pair*>(mem);
     cout << numbers->a;
 }

 return EXIT_SUCCESS;
}

aaaaa 内容:notacat

[scd11@VM11 ~]$ ./shteste

无法获得共享内存:权限被拒绝

【问题讨论】:

  • 您确定错误是由您显示的代码产生的吗?如果您没有演员表,我预计会出现此错误,如numbers = shmat(...)。但是演员应该照顾好它。
  • 你是对的......我复制了“固定”代码......我投射的那个(因此,不要抱怨转换)但出现分段错误。
  • 您应该检查来自shmgetshmat 的返回值。
  • 如果我用 strace 测试你的代码,我得到:“64 5327 shmget(0xffffffff, 8, IPC_CREAT|000) = 11534358 65 5327 shmat(11534358, NULL, 0) = -1 EACCES (Permission拒绝)”
  • C 允许隐式地将其他指针类型转换为void* 或从void* 转换,C++ 要求您进行转换。

标签: c++ linux segmentation-fault ipc shared-memory


【解决方案1】:

这可能是权限问题。您可以检查shmgetshmat 的返回值,并使用perror 打印这样的人类可读错误消息。

#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

struct my_pair {
  int a;
  int b;
};

int main()
{
  key_t key = ftok("aaaaa", 1);
  int shmid = shmget(key, sizeof(my_pair), IPC_CREAT | 0777);
  if (shmid == -1) {
      perror("Could not get shared memory");
      return EXIT_FAILURE;
  }

  my_pair *numbers;
  void* mem = (my_pair*) shmat(shmid, NULL, 0);
  if (mem == reinterpret_cast<void*>(-1)) {
      perror("Could not get shared memory location");
      return EXIT_FAILURE;
  } else {
      numbers = reinterpret_cast<my_pair*>(mem);
      cout << numbers->a;
  }

  return EXIT_SUCCESS;
}

【讨论】:

  • 您是绝对正确的:“无法获取共享内存位置:权限被拒绝”。我应该问系统管理员还是我作为用户/开发人员可以做些什么?
  • @VictorMarconi:不,您应该正确设置权限 :-) 看看我的回答!
  • 感谢大家。所有答案都有帮助......每个问题都有一点。错误的许可。因此,我不能再次使用相同的密钥(ftok)。非常感谢。
【解决方案2】:

这是一个权限问题。

the shmget() documentation:

概要

#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);

...

描述

...

  • shm_perm.mode 的低九位设置为 shmflg 的低九位。

您没有设置任何权限位。你调用的shmflag的低九位全为零:

int shmid = shmget(key, sizeof(my_pair), IPC_CREAT);

您需要设置适当的权限,如下所示:

int shmid = shmget(key, sizeof(my_pair), IPC_CREAT|0640);

您可能还必须使用ipcrm 来删除当前的共享内存段,因为它会在不正确的权限下保持原样。即使您更改了代码,您的 shmget() 调用也会返回现有段的 id - 由于缺少权限而无法附加的那个。

首先使用ipcs -a列出共享内存段,然后使用ipcrm -m shmidipcrm -M shmkey删除权限不正确的段。

【讨论】:

  • 感谢大家。所有答案都有帮助......每个问题都有一点。错误的许可。因此,我不能再次使用相同的密钥(ftok)。非常感谢。
【解决方案3】:

你只是忘记设置权限:

int shmid = shmget(key, sizeof(my_pair), IPC_CREAT | 0777);

正如我在评论中已经提到的,失败命令的结果可以通过 strace 看到。

64 5327 shmget(0xffffffff, 8, IPC_CREAT|000) = 11534358
65 5327 shmat(11534358, NULL, 0) = -1 EACCES (Permission denied)"

如果您的文件“aaaaa”已存在,则该代码适用于我。

【讨论】:

    【解决方案4】:

    根据ftok手册页:

    The ftok() function uses the identity of the file named by the given
    pathname (which must refer to an existing, accessible file).
    

    使用现有文件,您的代码将起作用。

    您也可以使用:

    key = IPC_PRIVATE
    

    这对于本示例来说已经足够了,但不适用于真正的 IPC。

    【讨论】:

    • 感谢大家。所有答案都有帮助......每个问题都有一点。错误的许可。因此,我不能再次使用相同的密钥(ftok)。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 2018-06-17
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    相关资源
    最近更新 更多