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

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

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

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

3 ответа

Решение

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

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

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

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

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

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

Зависит от того, как вы создали семафор, чтобы сделать это с помощью семафора IPC, см. Semaphore.c: Иллюстрация передачи простого семафора для примера.

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

Для этого ваш семафор должен храниться в области, совместно используемой родительским и дочерним процессами, например, совместно используемой памяти, а не просто создаваться в стеке или в куче, потому что он будет скопирован, когда процесс разветвится.

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

Семафор может быть разделен между потоками или процессами. Межпроцессное совместное использование реализовано на уровне операционной системы. Два или более разных процесса могут совместно использовать один и тот же семафор, даже если эти процессы не были созданы путем разветвления одного родительского процесса.

Посмотрите этот пример для совместного использования безымянного семафора 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,

Попробуй это

child и parent будут увеличивать переменную общего доступа в качестве альтернативы

#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);
}
Другие вопросы по тегам