未命名信号量 POSIX IPC

Unnamed semaphore POSIX IPC

我分配了一个整数大小的共享内存段。

标准输出的预期结果应该是:

P: 1
C: 2

但它是:

C: 1
P: 2

为什么在父进程完成并解锁共享内存段之前子进程不会被阻塞?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
#include <semaphore.h>

#define SHMSEGSIZE sizeof(int)

int main(void){

   pid_t pid;
   int shmID;
   int *shared_mem;

   /* initializing shared memory */
   shmID  = shmget(IPC_PRIVATE, SHMSEGSIZE, IPC_CREAT | 0644);
   shared_mem  = (int *)shmat(shmID, 0, 0);
   *shared_mem = 0;

   /* initializing semaphore */
   sem_t sem;
   int pshared = 1; // !=0 for processes, =0 for threads
   int value = 1; // number of processes at a time
   sem_init(&sem, pshared, value); // initialize the semaphore

   pid = fork();

   if(pid>(pid_t)0){ // parent
       sem_wait(&sem);
       sleep(6);
       *shared_mem += 1;
       printf("P: %d\n", *shared_mem);
       sem_post(&sem);
       exit(EXIT_SUCCESS);
   } // parent

   if(pid==(pid_t)0){ // child
       sleep(3);
       sem_wait(&sem);
       *shared_mem += 1;
       sem_post(&sem);
       printf("C: %d\n", *shared_mem);
       exit(EXIT_SUCCESS);
   } // child

   /* fork() failed */
   printf("Failed to fork().");
   exit(EXIT_FAILURE);
}

编译:

gcc -o executable sem.c -pthread

sem_t 本身必须在共享内存中才能成为 "pshared"。

struct my_shared_mem {
  sem_t sem;
  int   value;
};

... later ...

 struct my_shared_mem *shared;

 shmID  = shmget(IPC_PRIVATE, sizeof(*shared), ...);
 shared = shmat(shmID, ...);
 shared->value = 0;
 sem_init(&shared->sem, 1, 1);
 ...

无论何时您进行分叉,child 进程都会继承 parent 进程地址 space 的副本。因此变量 sem 将被复制到 child 的地址 space。在 parent 中所做的任何更改都不会反映在 child 中。 (sem_wait 基本上是递减信号量的值)

前面提到的一种方法是将信号量放在共享内存段中。
另一种方法是使用 semget 调用创建一个 system-wide 信号量(参考 man semget)。这里的接口比 pthread 库的接口复杂一点。您将必须使用 semctl 设置值(使用 union semun)并使用 semop(使用 struct sembuf)执行信号量操作。这个信号量是一个具有密钥的 IPC(在 semget 调用中传递)。您可以使用 ipcs -s

查看 system-wide 信号量