views:

129

answers:

2

Hi,

I am writing a server program where it receives message from client and broadcast message to all previous clients. I need to create a shared memory between processes, but it seems that the shared memory is not working.

Here is my code:

 int shmid2; key_t key2; void* shm2;
 string name_list;
 key2=ftok("tmp",'d');
 //create
 if ((shmid2 = shmget ( key2, sizeof(char)*1000, IPC_CREAT | 0666)) < 0) {
         perror("shmget2");
         exit(1);}
 //attach
 shm2 = shmat(shmid2, (void *)0, 0) ;
 name_list= (char*) shm2;
 if ( shm2 == (char *) -1) {
        perror("shmat2");
        exit(1);}
 ... do other things...
  switch (pid=fork()){
  case -1:
  { perror("ERROR on fork");
  break;}
  case 0://children
  { 
  ...modify name_list by getting message and append message to name_list..
  name_list.append(message);
  break;}
  default://parent
  close(connection);
  }

When I modify name_list in the children process, it seems that this modification is not seen by other processes. Can anyone give any suggestions? Thanks!!

UPDATE: I tried to change to this as suggested, but still does not work.

name_list = (char*) shmat(shmid2, (void *)0, 0) ;

Anyone can help me on this? Many thanks!

+1  A: 

When you assign the std::string object name_list to the pointer you get from shared memory:

string name_list;
// ...
shm2 = shmat(shmid2, (void *)0, 0) ;
name_list= (char*) shm2;
// ...
name_list.append(message);

you're calling the string's assignment operator, which copies the pointer it's given into new memory. When your code manipulates name_list, it's manipulating the copy, leaving shared memory untouched.

It looks like you're trying to write to shared memory from one process, and read from it in another process, which is not a trivial problem to solve. Figuring out which process can read and write which pieces of memory is tricky, as is maintaining cache coherency. Look up producer-consumer circular ring buffers (either on Google or here on Stack Overflow) for some standard solutions to this problem.

To answer your original question, once you've manipulated the string in local memory, you need to put it back in shared memory. This will do in a pinch:

if(name_list.size() <= 1000) {
    memcpy(shm2, name_list.data(), name_list.size());
} else {
    // error: name list overflowed shared memory
}

You could also manipulate shared memory directly, using the pointer shm2, using C pointers directly, taking care not to overflow your 1000-byte buffer.

Commodore Jaeger
Hi Commodore, your answer seems to be close to the solution. Excuse me if I am being stupid here, but i still dont understand why i am leaving shared memory untouched. Could you please explain more in detail? Thanks!!
Qii
I was thinking the same. @Qii: `name_list= (char*) shm2;` creates a string. In the string constructor it COPIES the data. So when you change name_list it is changing the variable which has nothing to do with the char* you constructed the object way (once again because its copied). To make things easier i suggest not using objects and use raw data (ints, chars, float and arrays and simple structs)
acidzombie24
Thanks Commodore and acidzombie24! I spent hours trying to figure out what went wrong. Now it's a big relief.
Qii
HI guys, bad news, I tried name_list = (char*) shmat(shmid2, (void *)0, 0) as suggested, but still not working..
Qii
A: 

To summarize: If you use string class, you will always manipulate a copy of the shared memory.

Two solutions: 1. Don't use string but standard C method to directly manipulate the char array (strcat for example to append characters) 2. Once you have finished modifying your name_list, copy it back to the shared memory.

Version 1 is faster. Version 2 is simpler.

Benoit Thiery