how to have correctly multiple variables in same shared memory segment

Viewed 582

I am trying to have 2 integers in the same memory segment. My code is the following:

int main()
{
  int *a;
  int *b;
  int id;
  id = shmget(IPC_PRIVATE,10,0666);
  a = (int *) shmat(id, (void*)0, 0);
  b = (int *) shmat(id, (void*)0, 0);
  *a = 5;
  *b = 10;
  printf("%d\n",*a);
  printf("%d\n",*b);
}

This prints 10 twice. Could anyone explain me why does this happen and how to solve it?

Extra question: If I had char * instead of int would it be necessary to do malloc(sizeof(char)*10) or the shmat call does the job in some way?

Thanks in advance!

1 Answers

First, you always want to use malloc rather than shared memory when possible. Even when doing IPC, simple pipes are typically more efficient.

Back, to your question, here are some explanations to your code

int main()
{
  int *a;
  int *b;
  int id;

  /* 'shmget' creates a shared memory segments of size 10,
     basically reserving 10 bytes of RAM/Swap. This memory is not 
     accessible in your virtual memory yet */   
  id = shmget(IPC_PRIVATE,10,0666);

  /* `shmat` maps the shared memory from above and makes it accessible in
     your virtual memory. `a` points to the beginning of the memory segment */ 
  a = (int *) shmat(id, (void*)0, 0);

  /* Here we map the same shared memory again into a different place in the
     virtual memory. But even if `a` and `b` points to different memory
     addresses, those addresses are backed by the same segment in RAM/Swap */  
  b = (int *) shmat(id, (void*)0, 0);

  *a = 5;
  *b = 10; /* because `*a` and `*b` are backed by the same RAM/Swap, */ 
           /* this will allso overwrite `*a`                        */

  printf("%d\n",*a);
  printf("%d\n",*b);
}

To solve this, you have basically two options. Either have two shared memory segments, one for a and one for b. Or you make one segment large enough to hold for both a and b to point to different places in the segment:

First solution:

/* This uses two segments */
int *a;
int *b;
int id1;
int id2;
id1 = shmget(IPC_PRIVATE,sizeof(int),0666);
id2 = shmget(IPC_PRIVATE,sizeof(int),0666);
a = (int *) shmat(id1, (void*)0, 0);
b = (int *) shmat(id2, (void*)0, 0);

Second solution:

/* This uses one segments */
int *a;
int *b;
int id;
/* Allocate enough memory for 2 int */
id = shmget(IPC_PRIVATE, 2*sizeof(int), 0666);
/* Map that memory into virtual memory space */
a = (int *) shmat(id, (void*)0, 0);
/* `a` points to the first int in a sequence of 2 ints, let `b` point to 
   the next one. */
b = a + 1;

As always, this code has omitted error checking for brevity. Adding error checking is left as an exercise for the reader.

To the extra question, neither malloc or any shared memory function cares about what you are going to store in the allocated memory. They just give you a sequence of char. It is your job to calculate how many char you need. (and btw sizeof(char) is always 1)

Related