C 信号量未按预期锁定

C semaphore not locking as intended

我一直在尝试通过这个简单的售票程序来学习信号量。唯一的问题是当前的信号量没有保护 numTicketsticketsSold 的值。我发现这个是因为有时售出的门票总数加起来会达到 51。

信号量的实现是否正确?

#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>

int numTickets;
sem_t mySem;

void* sell_ticket(void *sellerNum) {
  int sell = (int) sellerNum;
  int ticketsSold = 0;

  while (numTickets > 0) {
    srand ( time(NULL) );
    int random_number = rand();
    for (int i = 1; i < random_number % 5 ; i++) {
      if (numTickets > 0) {
        sem_wait(&mySem);
        numTickets--;
        ticketsSold++;
        printf("Seller # %d  sold a ticket. Tickets left: %d\n", sell, numTickets);
        sem_post(&mySem);
      }
    }
  }
  printf("Seller #%d noticed all tickets sold! (I sold %d myself) \n", sell, ticketsSold);
}

int main() {
  numTickets = 50;
  int numSellers = 4;
  sem_init(&mySem, 0, 1);

  pthread_t sellerThread;

  for (int i = 0; i < numSellers; i++) {
    pthread_create(&sellerThread, NULL, sell_ticket, (void *)i);
  }
  for (int i = 0; i < numSellers; i++) {
    pthread_join(sellerThread, NULL);
  }
  printf("All tickets sold!\n");
  return 0;
}

我相信我可以看出您的代码有两个问题:

1) 由于您启动了多个线程(每个卖家一个线程),因此您应该有一个 p_threads 数组,而不仅仅是一个线程。否则,pthread_join 不会加入所有创建的线程,而只会加入最后一个线程(因为每次创建新线程,都会覆盖先前创建的线程的句柄)

您的主要内容应类似于以下内容:

int main() {
  numTickets = 50;
  int numSellers = 4;
  sem_init(&mySem, 0, 1);

  pthread_t sellerThread[4];

  for (int i = 0; i < numSellers; i++) {
    pthread_create(&sellerThread[i], NULL, sell_ticket, (void *)i);
  }
  for (int i = 0; i < numSellers; i++) {
    pthread_join(sellerThread[i], NULL);
  }
  printf("All tickets sold!\n");
  return 0;
}

2) 此外,就像 Gene 已经正确评论的那样,您还需要使用信号量来读取票数(在 ifwhile 条件测试中)。否则,您仍然可能会遇到一个线程正在写入而另一个线程正在读取的情况。

但是请注意,在整个循环持续时间内使用信号量将导致只有一个线程售出所有门票。

因此 sell_ticket 函数应该类似于:

void* sell_ticket(void *sellerNum) {
  int sell = (int) sellerNum;
  int ticketsSold = 0;

  while (true) {
    // Check the number of tickets left. If sold out break out of infinite loop
    sem_wait(&mySem);
    if (numTickets <= 0) {
      sem_post(&mySem);
      break;
    }
    sem_post(&mySem);

    srand ( time(NULL) );
    int random_number = rand();
    for (int i = 1; i < random_number % 5 ; i++) {
      // Wait for semaphore before reading numTickets value in if condtion
      sem_wait(&mySem);

      if (numTickets > 0) {
        numTickets--;
        ticketsSold++;
        printf("Seller # %d  sold a ticket. Tickets left: %d\n", sell, numTickets);
      }
       // Post after if
       sem_post(&mySem);
    }
  }
  printf("Seller #%d noticed all tickets sold! (I sold %d myself) \n", sell, ticketsSold);
}