Do forked child processes use the same semaphore?

前端 未结 3 632
南旧
南旧 2020-11-28 14:09

Let\'s say I create a semaphore. If I fork a bunch of child processes, will they all still use that same semaphore?

Also, suppose I create a struct with semaphores

3条回答
  •  一生所求
    2020-11-28 14:38

    Let's say I create a semaphore. If I fork a bunch of child processes, will they all still use that same semaphore?

    It depends how you created the semaphore, to do that with an IPC semaphore see semaphore.c: Illustration of simple semaphore passing for an example.

    Also, suppose I create a struct with semaphores inside and forked. Do all the child processes still use that same semaphore? If not, would storing that struct+semaphores in shared memory allow the child processes to use the same semaphores?

    For that to work your semaphore needs to be stored in an area shared between the parent and the child process like shared memory, and not just created on the stack or on the heap because it will be copied when the process forks.

    I'm really confused about how my forked child processes can use the same semaphores.

    The semaphore can be shared across threads or processes. Cross-process sharing is implemented on the operating system level. Two or more different processes can share the same semaphore even if those processes were not created by forking a single parent process.

    See this example for sharing an unnamed UNIX semaphore between a parent process and its child (to compile with gcc you'll need the -pthread flag):

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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);
      }
    }
    

    The output will be:

    parent starts waiting: 0
    child unlocks semaphore: 0
    parent finished waiting: 0
    parent starts waiting: 1
    child unlocks semaphore: 1
    parent finished waiting: 1
    ...
    

    You may want to read Semaphores in Linux as well, but be aware that the example of UNIX semaphores across fork given doesn't work because the author forgot to use the MAP_ANONYMOUS flag in mmap.

提交回复
热议问题