Shared Memory With Two Processes In C?

2019-02-10 18:46发布

问题:

I want to do the following:

Parent process creates a child process. Then the child process reads n int's from the user and store them in a shared memory. The parent process then displays them.

I reached the following:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSIZE 27
int main() {
   int shmid;
   int *shm;
   int *n;

   if(fork() == 0) {
      shmid = shmget(2009, SHMSIZE, 0);
      shm = shmat(shmid, 0, 0);
      n = shm;
      int i;
      for(i=0; i<5; i++) {
         printf("Enter number<%i>: ", i);
         scanf("%d", n++);
      }
      printf ("Child wrote <%d>\n",shm);
      shmdt(shm);
   }
   else {
      wait();
      int *s;
      shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);
      shm = shmat(shmid, 0, 0);
      s = shm;
      wait(NULL);
      printf ("Parent reads <%d>\n",shm) ;
      shmdt(shm);
      shmctl(shmid, IPC_RMID, NULL);
   }
   return 0;
}

And the output is just this line:

Enter number<1>:

And if I entered a number, let's say 25, it outputs this:

Parent reads <r>

r: random -ve number changes every time I execute the code

It never went through the child process code ! Am I doing this in a wrong way ?

回答1:

Ok, better collect in an answer instead...

There are several problems with you program. If you enable warnings when building (I use -Wall -Wextra) a lot of them will be quite evident.

The first two problems I already mentioned in my comments, but I explain them here:

  1. The first is the call to wait(). There is no wait function in C or POSIX that takes no argument.
  2. The second problem is the scanf call, you are calling it with *++, where *n takes the value of the memory pointed to by n which most likely can result in a crash. Remove the asterisk.
  3. The third problem is that you treat the shared memory as both an array of integers (with n) and as a string. You cant really do both, pick one or the other.
  4. You create the shared memory in the parent process, but wait for the child process to finish before you create the memory.
  5. There is a race condition between the parent and child process, since the share memory might be created after the child tries to access it.

Edit I came up with this instead, which seems to work for me. I added comments on the things I changed.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h>  /* Needed for the wait function */
#include <unistd.h>    /* needed for the fork function */
#include <string.h>    /* needed for the strcat function */
#define SHMSIZE 27
int main() {
   int shmid;
   char *shm;

   if(fork() == 0) {
      shmid = shmget(2009, SHMSIZE, 0);
      shm = shmat(shmid, 0, 0);
      char *s = (char *) shm;
      *s = '\0';  /* Set first location to string terminator, for later append */
      int i;
      for(i=0; i<5; i++) {
         int n;  /* Variable to get the number into */
         printf("Enter number<%i>: ", i);
         scanf("%d", &n);
         sprintf(s, "%s%d", s, n);  /* Append number to string */
      }
      strcat(s, "\n");  /* Append newline */
      printf ("Child wrote <%s>\n",shm);
      shmdt(shm);
   }
   else {
      /* Variable s removed, it wasn't used */
      /* Removed first call to wait as it held up parent process */
      shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);
      shm = shmat(shmid, 0, 0);
      wait(NULL);
      printf ("Parent reads <%s>\n",shm) ;
      shmdt(shm);
      shmctl(shmid, IPC_RMID, NULL);
   }
   return 0;
}

Do note that point 5 in the list above have not been resolved.



回答2:

Your description seems to not be correct since there is no code that outputs "Parent Wrote <>".

You are reading numbers and storing them as int in *n++, but then you are appending a '\n' character to the n-int array and you are treating shm as a string?

It seems to me that in your child you are creating a shared memory, writing to it and then closing (discarding) the shared memory. Then your second part opens a new shared memory with the same segment, but yet it is a new shared memory. Normally one process creates a shared memory, then the second opens it and when the last process closes the shared memory, then it is freed by the OS.



回答3:

One problem is that the child process is attempting to use get the shared memory before it has been created by the parent. The parent has a wait() call before creating the shared memory, so it won't exist when the client tries to retrieve the id. Even if the wait() call is moved, it may not work because there is a race condition. The call to shmget may need to precede the fork call (or use some synchronization to make sure it actually exists before retrieving it in the child process).

And (as others have already pointed out), the child is attempting to write integers to the memory while the reading (printing of it) tries to treat it as a character string.



回答4:

My problem was so stupid. I need to provide the Child process with the ability to write into the SHM. This line in the if-block :

shmid = shmget(2009, SHMSIZE, 0);

Will become like this:

shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);

Thanks to you all and especially to @JoachimPileborg :)