未命名的信号量POSIX IPC

时间:2015-04-29 16:57:11

标签: c unix posix semaphore

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

stdout的预期结果应该是:

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

2 个答案:

答案 0 :(得分:2)

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);
 ...

答案 1 :(得分:1)

每当fork时,子进程都会继承父进程的地址空间的副本。因此,变量sem将被复制到子地址空间。父母所做的任何更改都不会反映在孩子身上。 (sem_wait基本上减少了信号量的值)

如前所述,一种方法是将信号量放在共享内存段中。
另一种方法是使用semget调用创建系统范围的信号量(请参阅man semget)。这里的接口比pthread库一点复杂一点。您必须使用semctl设置值(使用union semun)并使用semop执行信号量操作(使用struct sembuf)。该信号量是具有密钥的IPC(在semget调用中传递)。您可以使用ipcs -s

查看系统范围的信号量