在C中使用信号量和共享内存

时间:2017-06-17 14:26:55

标签: c fork semaphore shared-memory

程序应该创建200000个整数并将2000写入共享内存。分叉进程应该从共享内存读取2000,父进程应该将下一个2000写入共享内存。

如果我在没有睡眠的情况下使用下面的代码,父母首先创建所有200000个整数,然后孩子从共享内存中读取相同的整数。

随着睡眠,一切看起来都不错,但我们必须使用信号量。

shm.c(parent):

    #include <stdio.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/resource.h>
    #include <sys/wait.h>

    #define N_DATA 200000
    #define N_SHARED 2000
    #define LOCK       -1
    #define UNLOCK      1

    static struct sembuf semaphore;

    char shmidArg[32];
    char semidArg[32];
    int *shmData;
    int i, j;
    int status;
    char *strsignal(int sig);
    pid_t pid;

    static int shmid;
    static int semid;

    char *strsignal(int sig);

    /** Semaphore Operation */
    static int semaphore_operation (int op) {
       semaphore.sem_num = 1;
       semaphore.sem_op = op;
       semaphore.sem_flg = IPC_NOWAIT;
       if( semop (semid, &semaphore, 1) == -1) {
          perror(" semop ");
          exit (EXIT_FAILURE);
       }
       return 1;
    }

    int main(int argc, char **argv) {
      /* Ein Shared-Memory-Segment einrichten */
      shmid = shmget(IPC_PRIVATE, N_SHARED*sizeof(int), IPC_CREAT | SHM_R | SHM_W);
      if (shmid == -1) {
       perror("shmid");
       exit(1);
      }

      printf("Shared-Memory-ID: %d\n",shmid);

      /* Pointer zu Shared-Memory-Segment erhalten */
      shmData = (int *)shmat(shmid,0, 0);
      if (shmData == (int *)(-1)) {
          perror("shmat");
          exit(1);
      }

      /* Semaphore anlegen */
      semid = semget(IPC_PRIVATE, 1, IPC_CREAT | SHM_R | SHM_W);
      if (semid < 0) {
       perror("semid");
       exit(1);
      }

      printf ("Semaphor-ID : %d\n", semid);

      /* Semaphor mit 1 initialisieren */
    if (semctl (semid, 0, SETVAL, (int) 1) == -1) {
       perror("semctl");
    }

    snprintf(shmidArg,32, "%d", shmid);
    snprintf(semidArg,32, "%d", semid);

      /** erstellen des Kindprozesses */
      pid = fork();

      // Kindprozess
      if (pid == 0) {
        execlp("./shm_child",shmidArg,semidArg,NULL);
      } else if (pid < 0) {
            perror("Kindprozess konnte nicht erzeugt werden!");
            return 1;
        }
      // Elternprozess
      else {
        /** ininitalisieren des Zufallsgenerator durch aktuellen Zeitstempel */
        srand48(time(NULL));
        for(i=0;i<N_DATA;i=i+N_SHARED) {
          semaphore_operation(LOCK);
          for (j=0; j<N_SHARED; j++) {
            shmData[j] = lrand48();
            //MSZ
            //printf("SHM-->%d-->%d\n",i+1,shmData[i]);
          }
    //      if(i == 0 || i == 2000) {
            printf("Parent-->%d-->0-->%d\n",i,shmData[0]);
            printf("Parent-->%d-->1999->%d\n",i,shmData[1999]);
    //      }
          semaphore_operation(UNLOCK);
          //sleep(1);
        }
      }

      //MSZ
      //sleep(2);
      printf("PID: %d\n", pid);

      if (waitpid(pid, &status, 0) == -1) {
            perror("wait konnte nicht erzeugt werden!");
            return 1;
        }

        if (WIFEXITED(status)) {
            printf("Exitcode: %d\n", WEXITSTATUS(status));
        semctl (semid, 0, IPC_RMID, 0);
        shmctl (shmid, IPC_RMID, NULL);
        //If process terminaded by a signal
        } else if (WIFSIGNALED(status)) {
            printf("Signal: %d %s\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
        semctl (semid, 0, IPC_RMID, 0);
        shmctl (shmid, IPC_RMID, NULL);
        }

    }

shm_child.c(孩子):

        #include <stdio.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>

    #define N_DATA 6000
    #define N_SHARED 2000
    #define LOCK       -1
    #define UNLOCK      1

    int i,j;
    int *shmData;
    static int shmid;
    static int semid;
    static struct sembuf semaphore;


    /** Semaphore Operation */
    static int semaphore_operation (int op) {
       semaphore.sem_num = 0;
       semaphore.sem_op = op;
       semaphore.sem_flg = SEM_UNDO;
       if( semop (semid, &semaphore, 1) == -1) {
          perror(" semop ");
          exit (EXIT_FAILURE);
       }
       return 1;
    }

    int main(int argc, char **argv) {
      shmid = atoi(argv[0]);
      semid = atoi(argv[1]);

      printf("\nshm_child shared memoryid:%d\n",shmid);
      printf("shm_child Semaphoren-ID:%d\n",semid);

      /* Pointer auf Shared-Memory erstellen */
      shmData = (int *)shmat(shmid,0,0);
      if (shmData == (int *)(-1)) {
          perror("shmat");
          exit(1);
      }


    for(i=0;i<N_DATA;i=i+N_SHARED) {
      semaphore_operation(LOCK);
      for(j=0;j<N_SHARED;j++) {
        //printf("%d-->%d --> %d\n",i,j+1,shmData[j]);
      }
    //  if(i == 0 || i == 2000) {
        printf("child-->%d-->0-->%d\n",i,shmData[0]);
        printf("child-->%d-->1999->%d\n",i,shmData[1999]);
    //  }
      semaphore_operation(UNLOCK);
      sleep(1);
    }

      return 0;
    }

请帮助我们 谢谢你们

编辑:非常感谢您的回答。我无法标出正确的答案,因为我不知道它的正确性。但我不想再尝试了。 15个小时就足够了

1 个答案:

答案 0 :(得分:0)

作者程序应给予读者阅读权限,并等待阅读完成。之后,读者应给予作者继续许可,并等待写作完成。

使用单个信号量无法实现此目标。你需要两个,分别是:

    // parent aka writer
    writer_barrier = semaphore(UNLOCKED);
    reader_barrier = semaphore(LOCKED);
    start_reader();
    while(...) {
        lock(writer_barrier);
        write_data();
        unlock(reader_barrier);
    }

    // child aka reader
    while(....)
        lock(reader_barrier);
        read_data();
        unlock(writer_barrier);
    }