简体   繁体   中英

Linux Shared Memory with C++: Segmentation Fault

I'm following the Linux Programming Interface book (page 1004-1005).

I know the book uses C. But I'd like to implement the same behavior in C++. That is: share a struct between processes through shared memory.

#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;
}

It gives me this error:

shteste.cpp: In function 'int main()':

shteste.cpp:18: error: invalid conversion from 'void*' to 'my_pair*'

I understand that C++ is more strict. If I cast the return of shmat to (my_pair *), it compiles but gives me segmentation fault during execution.

Is it possible (how) to use Linux / C shared memory facilities with C++ ?

I'm compiling with: G++ 4.4.7: g++ shteste.cpp -o shteste -std=c++0x

Thanks...

EDIT: Following all sugestions, this is the code now:

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 contents: notacat

[scd11@VM11 ~]$ ./shteste

Could not get shared memory: Permission denied

This is likely a permissions issue. You can check the return values of shmget and shmat and use perror to print a human-readable error message like this.

#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;
}

You simple forget to set the permissions:

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

As I already mentioned in my comment, the result of the failing command can be seen with strace.

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

If your file "aaaaa" is existing, the code works for me.

This is a permissions issue.

Per the shmget() documentation :

SYNOPSIS

 #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); 

...

DESCRIPTION

...

  • The low-order nine bits of shm_perm.mode are set to the low-order nine bits of shmflg .

You didn't set any permission bits. The low-order nine bits of shmflag in your call are all zero:

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

You need to set the proper permissions, something like this:

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

You will also likely have to use ipcrm to remove the current shared-memory segment, as it will remain as-is with the incorrect permssions. Even if you change your code, your shmget() calls will return the id of the existing segment - the one that you can't attach because the permissions are missing.

First, use ipcs -a to list the shared memory segments, then use ipcrm -m shmid or ipcrm -M shmkey to remove the segment with incorrect permissions.

According to ftok man page:

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

With existing file your code will work.

Alternatively you can use:

key = IPC_PRIVATE

which will be sufficient for this example, but will not work for real IPC.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM