Используют ли раздвоенные дочерние процессы один и тот же семафор?

предположим, я создаю семафор. Если я раскрою кучу дочерних процессов, все ли они будут использовать тот же семафор?

кроме того, предположим, что я создаю структуру с семафорами внутри и раздвоенными. Все ли дочерние процессы используют один и тот же семафор? Если нет, позволит ли хранение этой структуры+семафоров в общей памяти дочерним процессам использовать те же семафоры?

Я действительно смущен тем, как мои раздвоенные дочерние процессы могут использовать одни и те же семафоры.

3 ответов


предположим, я создаю семафор. Если я раскрою кучу дочерних процессов, все ли они будут использовать тот же семафор?

если вы используете семафор SysV IPC (semctl), тогда да. Если вы используете семафоры POSIX (sem_init), тогда да, но только если вы передадите значение true для аргумента pshared при создании и поместите его в общую память.

кроме того, предположим, что я создаю структуру с семафорами внутри и раздвоенными. Сделать все дочерние процессы все еще используют тот же семафор? Если нет, позволит ли хранение этой структуры+семафоров в общей памяти дочерним процессам использовать те же семафоры?

что значит быть "семафорами внутри"? Ссылки на семафоры SysV IPC будут общими, потому что семафоры не принадлежат ни одному процессу. Если вы используете семафоры POSIX или создаете что-то из мьютексов и кондваров pthreads, вам нужно будет использовать общую память и атрибут pshared (pthreads имеет атрибут pshared для condvars и мьютексы а)

обратите внимание, что анонимные mmaps, созданные с помощью MAP_SHARED для этих целей флаг считается (анонимной) общей памятью, поэтому нет необходимости создавать именованный сегмент общей памяти. обычная память кучи не будет совместно использоваться после вилки.


предположим, я создаю семафор. Если я развил кучу дочерних процессов, они все еще будут использовать тот же семафор?

это зависит от того, как вы создали семафор, чтобы сделать это с помощью семафора IPC see семафор.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);
  }
}

в выход будет:

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

вы можете ознакомиться семафоры в Linux также, но имейте в виду, что пример семафоров UNIX через вилку не работает, потому что автор забыл использовать MAP_ANONYMOUS флаг mmap.


попробуй такое

ребенок и родитель будут увеличивать общую переменную альтернативно

#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>

struct test {
        sem_t mutex1;
        sem_t mutex2;
        int temp;
}test1;

int main(int argc, char **argv)
{
  int fd, i,count=0,nloop=10,zero=0,*ptr;
  struct test *testptr;
  //open a file and map it into memory
        sem_t mutex;
  fd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU);
  write(fd,&zero,sizeof(int));
  ptr = mmap(NULL, sizeof(struct test),PROT_READ |PROT_WRITE,MAP_SHARED,fd,0);
  close(fd);
  memcpy(ptr, &test1, sizeof(test1));
  testptr = (struct test *)ptr;
  // testptr = (struct test *)&test1;
  /* create, initialize semaphore */
  if( sem_init(&(testptr->mutex1),1,1) < 0)
    {
      perror("semaphore initilization");
      exit(0);
    }
  /* create, initialize semaphore */
  if( sem_init(&(testptr->mutex2),1,0) < 0)
    {
      perror("semaphore initilization");
      exit(0);
    }
  if (fork() == 0) { /* child process*/
    for (i = 0; i < nloop; i++) {
      sem_wait(&(testptr->mutex2));
      printf("child: %d\n", testptr->temp++);
      sem_post(&(testptr->mutex1));
    }
    exit(0);
 /* back to parent process */
  for (i = 0; i < nloop; i++) {
    sem_wait(&testptr->mutex1);
    printf("parent: %d\n", testptr->temp++);
    sem_post(&(testptr->mutex2));
  }
  exit(0);
}