Linux共享内存与C ++:分段错误

时间:2017-09-30 17:46:53

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

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

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

#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:在函数&#39; int main()&#39;:

     

shteste.cpp:18:错误:无效转换来自&#39; void *&#39;到&#39; my_pair *&#39;

我理解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

     

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

4 个答案:

答案 0 :(得分:2)

这可能是权限问题。您可以查看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;
}

答案 1 :(得分:2)

你很容易忘记设置权限:

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)"

如果您的文件&#34; aaaaa&#34;存在,代码适合我。

答案 2 :(得分:2)

这是权限问题。

the shmget() documentation

  

概要

because standard says so
     

...

     

说明

     

...

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

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

#include <sys/shm.h>

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

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

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

您还可能必须使用int shmid = shmget(key, sizeof(my_pair), IPC_CREAT|0640); 来删除当前的共享内存段,因为它将保持原样并且不正确的permssions。即使您更改了代码,您的ipcrm调用也会返回现有细分的ID - 您无法附加的细分,因为缺少权限。

首先,使用shmget()列出共享内存段,然后使用ipcs -aipcrm -m shmid删除权限不正确的段。

答案 3 :(得分:1)

根据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。