2017-05-06 26 views
0

我一直在試圖學習這個簡單的門票銷售計劃的信號量。唯一的問題是當前的信號量不能保護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的值。 –

回答

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)此外,像基因已經正確評價,您需要使用信號來讀取門票數量,以及(在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) –