C信号量没有按预期锁定

问题描述:

我一直在试图学习这个简单的门票销售计划的信号量。唯一的问题是当前的信号量不能保护numTicketsticketsSold的值。我发现这是因为有时卖出的总票数加起来最多为51.C信号量没有按预期锁定

是否正确执行信号量?

#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; 
} 
+0

我毫不客气的并行线程的专家,但预计在读numTickets(在'if'和'while')时,另一个线程正在写这是问题。您需要在受信号量保护的块内获得读取 - 修改 - 写入序列。 – Gene

+0

我已经尝试了上面的建议。不幸的是,经过各种测试,我得到了51的值。 –

我相信我可以看到两个问题与您的代码:

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)此外,像基因已经正确评价,您需要使用信号来读取门票数量,以及(在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); 
} 
+0

我已经通读了你的答案,我现在看到现在如何将信号放在我的周围,如果,而且是一个明智的选择。可悲的是,即使提供了代码。我偶尔会得到高于50的值。 –

+0

编辑这个工程,虽然真的必须是(1) –