分叉子进程使用相同的信号量吗?

jmn*_*ong 7 c linux fork semaphore shared-memory

假设我创建了一个信号量.如果我分叉一堆子进程,它们还会使用相同的信号量吗?

另外,假设我创建了一个内部和分叉信号量的结构.所有子进程是否仍然使用相同的信号量?如果没有,将结构+信号量存储在共享内存中是否允许子进程使用相同的信号量?

我真的很困惑我的分叉子进程如何使用相同的信号量.

bdo*_*lan 10

假设我创建了一个信号量.如果我分叉一堆子进程,它们还会使用相同的信号量吗?

如果您使用的是SysV IPC信号量(semctl),那么是.如果您正在使用POSIX信号量(sem_init),那么是,但仅当您在创建时为pshared参数传递true值并将其放在共享内存中时.

另外,假设我创建了一个内部和分叉信号量的结构.所有子进程是否仍然使用相同的信号量?如果没有,将结构+信号量存储在共享内存中是否允许子进程使用相同的信号量?

你是什​​么意思'内部的信号量'?将共享对SysV IPC信号量的引用,因为信号量不属于任何进程.如果您正在使用POSIX信号量,或者使用pthreads互斥锁和condvars构建某些内容,则需要使用共享内存和pshared属性(pthreads也具有condvars互斥锁的pshared属性)

请注意,使用MAP_SHARED标志创建的匿名mmaps 计为(匿名)共享内存用于这些目的,因此不必实际创建命名共享内存段.fork之后不会共享普通的堆内存.


小智 7

假设我创建了一个信号量.如果我分叉一堆子进程,它们还会使用相同的信号量吗?

这取决于你如何创建信号量,用IPC信号量来做到这一点请参见semaphore.c:简单信号量传递示例的插图.

另外,假设我创建了一个内部和分叉信号量的结构.所有子进程是否仍然使用相同的信号量?如果没有,将结构+信号量存储在共享内存中是否允许子进程使用相同的信号量?

为了实现这一点,您的信号量需要存储在父进程和子进程之间共享的区域(如共享内存)中,而不仅仅是在堆栈上或堆上创建,因为它将在进程分叉时被复制.

我真的很困惑我的分叉子进程如何使用相同的信号量.

信号量可以跨线程或进程共享.跨进程共享在操作系统级别上实现.两个或多个不同的进程可以共享相同的信号量,即使这些进程不是通过分支单个父进程创建的.

请参阅此示例,以便在父进程与其子进程之间共享未命名的UNIX信号量(要使用gcc进行编译,您需要使用该-pthread标志):

#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

int main(void)
{
  /* place semaphore in shared memory */
  sem_t *sema = mmap(NULL, sizeof(*sema), 
      PROT_READ |PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,
      -1, 0);
  if (sema == MAP_FAILED) {
    perror("mmap");
    exit(EXIT_FAILURE);
  }

  /* create/initialize semaphore */
  if ( sem_init(sema, 1, 0) < 0) {
    perror("sem_init");
    exit(EXIT_FAILURE);
  }
  int nloop=10;
  int pid = fork();
  if (pid < 0) {
    perror("fork");
    exit(EXIT_FAILURE);
  }
  if (pid == 0) { 
    /* child process*/
    for (int i = 0; i < nloop; i++) {
      printf("child unlocks semaphore: %d\n", i);
      if (sem_post(sema) < 0) {
          perror("sem_post");
      }
      sleep(1);
    }
    if (munmap(sema, sizeof(sema)) < 0) {
      perror("munmap");
      exit(EXIT_FAILURE);
    }
      exit(EXIT_SUCCESS);
  }
  if (pid > 0) {
    /* back to parent process */
    for (int i = 0; i < nloop; i++) {
      printf("parent starts waiting: %d\n", i);
      if (sem_wait(sema) < 0) {
        perror("sem_wait");
      }
      printf("parent finished waiting: %d\n", i);
    }
    if (sem_destroy(sema) < 0) {
      perror("sem_destroy failed");
      exit(EXIT_FAILURE);
    }
    if (munmap(sema, sizeof(sema)) < 0) {
      perror("munmap failed");
      exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
  }
}
Run Code Online (Sandbox Code Playgroud)

输出将是:

parent starts waiting: 0
child unlocks semaphore: 0
parent finished waiting: 0
parent starts waiting: 1
child unlocks semaphore: 1
parent finished waiting: 1
...
Run Code Online (Sandbox Code Playgroud)

您可能也希望在Linux中读取Semaphores,但请注意,给定fork的UNIX信号量示例不起作用,因为作者忘记使用该MAP_ANONYMOUS标志mmap.