2011-10-16 66 views
0

我必須製作一個共享變量(初始值= 35的計數器)和5個線程的程序。我必須製作程序,以便每個線程訪問計數器的值並將其遞減1.這應該持續到計數器= 0爲止。多線程程序中的錯誤

這是我到目前爲止的代碼,但問題是隻有一個線程遞減計數器的值爲0.

#include <stdio.h> 
#include <time.h> 
#include <stdlib.h> 
#include <pthread.h> 

#define NTHREADS 5 
void *thread_function1(void *); 
void *thread_function2(void *); 
void *thread_function3(void *); 
void *thread_function4(void *); 
void *thread_function5(void *); 
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; 
short int counter = 35; 


main() 
{ 
    pthread_t thread_id[NTHREADS]; 
    pthread_t thread1, thread2, thread3, thread4, thread5; 
int status, status2, status3, status4, status5; 

status = pthread_create(&thread1, NULL, thread_function1, NULL); 
if(status!=0){ 
    fprintf(stderr,"thread 1 failed\n");  
} 

status2 = pthread_create(&thread2, NULL, thread_function2, NULL); 
if(status2!=0){ 
    fprintf(stderr,"thread 2 failed\n");  
} 

status3 = pthread_create(&thread3, NULL, thread_function3, NULL); 
if(status3!=0){ 
    fprintf(stderr,"thread 3 failed\n");  
} 

status4 = pthread_create(&thread4, NULL, thread_function4, NULL); 
if(status4!=0){ 
    printf("thread 4 failed\n");  
} 

status5 = pthread_create(&thread5, NULL, thread_function5, NULL); 
if(status5!=0){ 
    fprintf(stderr,"thread 5 failed\n");  
} 

//pthread_join(thread1, NULL); 
//int x = counter; 

printf("created all the threads \n"); 

printf("joining thread 1"); 
    pthread_join(thread1, NULL); 
printf("joining thread 2"); 
    pthread_join(thread2, NULL); 
printf("joining thread 3"); 
    pthread_join(thread3, NULL); 
printf("joining thread 4"); 
    pthread_join(thread4, NULL); 
printf("joining thread 5"); 
    pthread_join(thread5, NULL);       

    printf("Final counter value: %d\n", counter); 
} 

void *thread_function1(void *dummyPtr) 
{ 
    printf("Thread number %ld\n", pthread_self()); 

while(counter>0){ 
    srand(time(NULL)); 

    int r = rand()%3; 
    printf(" %d\n", r); 
    pthread_mutex_lock(&mutex1); 
    printf("entered the mutex"); 
    counter--; 
    printf(" %d\n", counter); 
    sleep(r); 
    pthread_mutex_unlock(&mutex1); 
    printf("mutex unlocked"); 
    pthread_yield(); 
} 

} 

void *thread_function2(void *dummyPtr) 
{ 
    printf("Thread number %ld\n", pthread_self()); 

while(counter>0){ 
    srand(time(NULL)); 

    int r = rand()%3; 
    printf(" %d\n", r); 
    pthread_mutex_lock(&mutex1); 
    printf("entered the mutex"); 
    counter--; 
    printf(" %d\n", counter); 
    sleep(r); 
    pthread_mutex_unlock(&mutex1); 
    pthread_yield(); 
} 

} 

void *thread_function3(void *dummyPtr) 
{ 
    printf("Thread number %ld\n", pthread_self()); 

while(counter>0){ 
    srand(time(NULL)); 
    int r = rand()%3; 
    printf(" %d\n", r); 
    pthread_mutex_lock(&mutex1); 
    printf("entered the mutex"); 
    counter--; 
    printf(" %d\n", counter); 
    sleep(r); 
    pthread_mutex_unlock(&mutex1); 
    pthread_yield(); 
} 

} 

void *thread_function4(void *dummyPtr) 
{ 
    printf("Thread number %ld\n", pthread_self()); 

while(counter>0){ 
    srand(time(NULL)); 

    int r = rand()%3; 
    printf(" %d\n", r); 
    pthread_mutex_lock(&mutex1); 
    printf("entered the mutex"); 
    counter--; 
    printf(" %d\n", counter); 
    sleep(r); 
    pthread_mutex_unlock(&mutex1); 
    pthread_yield(); 
} 

} 

void *thread_function5(void *dummyPtr) 
{ 
    printf("Thread number %ld\n", pthread_self()); 

while(counter>0){ 
    srand(time(NULL)); 

    int r = rand()%3; 
    printf(" %d\n", r); 
    pthread_mutex_lock(&mutex1); 
    printf("entered the mutex"); 
    counter--; 
    printf(" %d\n", counter); 
    sleep(r); 
    pthread_mutex_unlock(&mutex1); 
    pthread_yield(); 
} 

} 

任何人都可以請幫忙嗎? 感謝

+0

爲什麼你有5個完全相同的線程函數呢? – asveikau

+0

我做錯了那部分。現在我只有一個線程函數,所有線程都可以訪問這個函數。 –

+0

請通過一個體面的編譯器運行你的代碼,並啓用警告,'-Wall'左右,然後再發布。我用gcc得到10。最重要的是關於未知的'sleep'和'pthread_yield'。如果我使用正確的標題,它會立即發現Antti指出的錯誤。 –

回答

2
int r = rand()%3; 
/* ... */ 
sleep(rand); 

r爲0至2之間的隨機數,但你睡rand秒,這是一個功能,這將是隱式強制轉換爲一個unsigned int的地址 - 這樣的線程將睡很長時間。改爲使用sleep(r);

另外請注意,你讀counter,而不是持有互斥鎖(在while(counter > 0)),這可能會導致程序錯誤的工作取決於架構,緩存和編譯器優化。您應該鎖定互斥鎖,將counter的值讀取到本地變量,然後解鎖互斥鎖並檢查值是否爲正數。

+0

嗨,謝謝。該程序正在運行。但是現在只有thread1遞減了downt0 0的值。還有什麼是不正確的嗎? –

+0

爲什麼你認爲只有thread1遞減值爲0? – Antti

+0

因爲只有thread1有權訪問CPU,因此線程2到5沒有機會運行。這就是爲什麼我正在試驗產量和睡眠,以便其他線程有機會運行 –

1

雖然安蒂找到一個很好的,我有幾個意見:

  • 你並不需要五個相同的功能。您只能有一個函數,並以不同的線程啓動它五次。

  • 你正在睡眠時鎖定互斥鎖。這意味着其他線程會在線程休眠時阻塞。我想你想在釋放鎖之後睡覺,以便其他線程可以在櫃檯。

  • 當您在while循環的條件中檢查計數器時,您正在讀取互斥鎖保護之外的計數器。無論您正在閱讀還是書寫,都需要在訪問共享資源時鎖定互斥鎖。如果你不這樣做,那麼你會有競爭條件。

  • 如果你按照我的建議,並在互斥體釋放後移動睡眠,那麼調用pthread_yield是不必要的,因爲睡眠也會產生。

+0

感謝您的意見。代碼現在看起來很整齊。爲什麼建議在讀取時使用互斥鎖?互斥鎖的目的是爲了確保數據不被破壞,對嗎? –

+1

您的while循環中的條件無法以原子方式進行評估,首先讀取計數器,然後進行比較。比方說,線程#1讀取計數器,它是1.然後有一個切換到線程#2,他也讀取計數器,它是1.線程2繼續並進行比較,進入循環,遞減計數器到0.現在線程1重新獲得控制權並使用值1進行比較,因爲它在線程#2遞減之前讀取該變量。你的計數器會再次遞減到-1。這被稱爲競賽條件。 – Miguel