用于同步的全局信号量 - 计数器

global semaphores for synchronisation - counter

下面我在两个不同的进程中增加一个计数器 1000 并使用全局信号量进行同步。但是iCounter不给我2000?有人可以向我解释为什么吗?

#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <fcntl.h>

#define SEM_NAME "/sync"
#define NUMBER_OF_PROCESSES 2

int main ()
{
  int iCounter = 0;
  pid_t pid[NUMBER_OF_PROCESSES];
  sem_t *sSem = sem_open (SEM_NAME,O_CREAT | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 1);
  int i, iStatus;
  
  for (i = 0; i < NUMBER_OF_PROCESSES; i++)
    {
      pid[i] = fork ();
      if (pid[i] < 0)
    {
      printf ("Could not create process\n");
      exit (1);
    }
      else if (pid[i] == 0)
    {
      int i;
      for (i = 0; i < 1000; i++)
        {
          sem_init(sSem, 0, 1);
          sem_wait (sSem);
          iCounter++;
          sem_post (sSem);
        }
      exit (0);
    }
    }
  for (i = 0; i < NUMBER_OF_PROCESSES; i++)
    waitpid (pid[i], &iStatus, WUNTRACED);
  printf ("Value of iCounter = %d\n", iCounter);
  sem_close (sSem);
  sem_unlink (SEM_NAME);
}

你有两个大问题:

  1. 您没有正确使用命名信号量。 sem_init() 仅用于匿名信号量,并且每个信号量只能使用一次,您在已经初始化的信号量上多次调用它。那是未定义的行为。

  2. 您的 iCounter 变量未在您创建的进程之间共享。

您的程序的以下修改使用 POSIX 共享内存分配它(并进行了一些常规清理):

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

#define SEM_NAME "/sync"
#define SHM_NAME "/counter"
#define NUMBER_OF_PROCESSES 2

int main() {
  int *iCounter = MAP_FAILED;
  pid_t pid[NUMBER_OF_PROCESSES];
  int iStatus;
  int ret = 0;
  int memfd = -1;
  
  sem_t *sSem = sem_open(SEM_NAME, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1);
  if (sSem == SEM_FAILED) {
    perror("sem_open");
    ret = 1;
    goto cleanup;
  }

  memfd = shm_open(SHM_NAME, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
  if (memfd < 0) {
    perror("shm_open");
    ret = 1;    
    goto cleanup;
  }

  if (ftruncate(memfd, sizeof *iCounter) < 0) {
    perror("ftruncate");
    ret = 1;
    goto cleanup;
  }
  iCounter = mmap(NULL, sizeof *iCounter, PROT_READ | PROT_WRITE, MAP_SHARED,
                  memfd, 0);
  if (iCounter == MAP_FAILED) {
    perror("mmap");
    ret = 1;
    goto cleanup;
  }
  close(memfd);
  *iCounter = 0;

  for (int i = 0; i < NUMBER_OF_PROCESSES; i++) {
    pid[i] = fork();
    if (pid[i] < 0) {
      fprintf(stderr, "Could not create process: %s\n", strerror(errno));
      ret = 1;
      goto cleanup;
    } else if (pid[i] == 0) {
      for (i = 0; i < 1000; i++) {
        sem_wait(sSem);
        (*iCounter)++;
        sem_post(sSem);
      }
      sem_close(sSem);
      return 0;
    }
  }
  for (int i = 0; i < NUMBER_OF_PROCESSES; i++)
    waitpid(pid[i], &iStatus, WUNTRACED);

  printf("Value of iCounter = %d\n", *iCounter);

 cleanup:
  if (sSem != SEM_FAILED) {
    sem_close(sSem);
    sem_unlink(SEM_NAME);
  }
  if (memfd >= 0)
    shm_unlink(SHM_NAME);

  return ret;
}

示例:

$ gcc -g -O -Wall -Wextra example.c -lrt -lpthread
$ ./a.out
Value of iCounter = 2000