2016-08-30 59 views
2

所以我有這個程序有2個線程從0增加到100個變量,它工作正常。條件變量程序適用於2個線程但不適用於3

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

int contor; 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void *incrementare(void *args) { 
    int id = (int)args; 
    while(1) { 
     pthread_mutex_lock(&mutex); 
     if (contor >= 100) { 
      pthread_cond_signal(&cond); 
      pthread_mutex_unlock(&mutex); 
      pthread_exit(NULL); 
     } 

     while (contor %2 == id) { 
     pthread_cond_wait(&cond,&mutex); 
     } 

     contor++; 
     printf("Thread %d increment: %d\n",id,contor); 


     pthread_cond_signal(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 
} 

int main(void) { 
    pthread_t th1, th2,th3; 

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) { 
     perror("Error!\n"); 
     exit(1); 
    } 
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) { 
     perror("Error!\n"); 
     exit(2); 
    } 


    pthread_join(th1, NULL); 
    pthread_join(th2, NULL); 

    pthread_mutex_destroy(&mutex); 
    pthread_cond_destroy(&cond); 

    return 0; 
} 

的結果是這樣的:

Thread 1 increment: 1 
Thread 0 increment: 2 
Thread 1 increment: 3 
Thread 0 increment: 4 
Thread 1 increment: 5 
Thread 0 incre.. and so on ,which is nice. 

但問題是,當我嘗試用3個線程,它不再工作,因爲他們再來找隨機。我只做了3個改變,我不知道問題是什麼。

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

int contor; 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void *incrementare(void *args) { 
    int id = (int)args; 
    while(1) { 
     pthread_mutex_lock(&mutex); 
     if (contor >= 100) { 
      pthread_cond_signal(&cond); 
      pthread_mutex_unlock(&mutex); 
      pthread_exit(NULL); 
     } 

     while (contor %3 == id) { 
     pthread_cond_wait(&cond,&mutex); 
     } 

     contor++; 
     printf("Thread %d increment: %d\n",id,contor); 


     pthread_cond_signal(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 
} 

int main(void) { 
    pthread_t th1, th2,th3; 

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) { 
     perror("Error!\n"); 
     exit(1); 
    } 
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) { 
     perror("Error!\n"); 
     exit(2); 
    } 
    if(pthread_create(&th3, NULL, &incrementare, (void *)2) < 0) { 
     perror("Error!\n"); 
     exit(3); 
    } 



    pthread_join(th1, NULL); 
    pthread_join(th2, NULL); 
     pthread_join(th3, NULL); 


    pthread_mutex_destroy(&mutex); 
    pthread_cond_destroy(&cond); 

    return 0; 
} 

它應該做同樣的權利?現在只有3。爲什麼它不工作?這是如何工作的

Thread 2 increment: 1 
Thread 2 increment: 2 
Thread 1 increment: 3 
Thread 1 increment: 4 
Thread 2 increment: 5 
Thread 1 increment: 6 
+4

與您的問題無關,但如果您聲明函數返回值,則應該返回一個值。即使你忽略返回的值。 –

+2

也與您的問題無關,但[pthread_create'](http://man7.org/linux/man-pages/man3/pthread_create.3.html)函數錯誤時不會返回「-1」。成功時返回'0',否則返回錯誤代碼。這意味着你檢查錯誤是錯誤的。 –

+5

在相同級別的優先級任務中,OS按內核喜歡的方式調度線程。如果你想強加一個特定的序列,你應該編碼約束。 – LPs

回答

2

如果你想線程以保證循環,你需要做一個線程等待,直到模N計數器(線程數)是特定 ID,直到它是什麼但是那個具體的id。有兩個ID,如果它不是一個,它必須是另一個。但有三個,有兩個破案,一個等待。 調度程序可以自由選擇要釋放的那兩個備用線程中的哪一個。

但是,如果你改變了這個:

while (contor %3 == id) 

這樣:

while (contor %3 != id) 

你會強制執行給定的線程將寫值被模其ID。

但是,這還不夠。你還需要喚醒全部服務員。之前,當你只有兩個線程時,總是有同一個服務員:「另一個人」不是活動線程。這個pthread_cond_signal將被定向到一個特定的目標線程(唯一沒有運行的線程),它自然也是下一個線程。

如果有三個或更多線程,則可能由pthread_cond_signal潛在喚醒的單線程可能不是具有contor模N id的那個線程。事實上,你擁有的線程越多,發生這種情況的可能性就越大。在這種情況下,線程回到等待狀態,但沒有其他人等待再次啓動。你不想讓這個機會。確保全部服務員醒來確保下一個將獲得信號。

不是解決這個只是發送另一個pthread_cond_signal的地方。相反,發送一個廣播,而不是:更改此:

pthread_cond_signal(&cond); 

這樣:

pthread_cond_broadcast(&cond); 

這將確保所有積極等待的線程最終在看着contor得到裂紋,而匹配contor的一個模N將有機會撞擊,打印,發送下一個廣播,然後回頭等待。

因此,爲了你的代碼的最小變化將是:

#include<stdio.h> 
#include<stdlib.h> 
#include<stdint.h>  // added for intptr_t 
#include<inttypes.h> // added for printf formatter for intptr_t 
#include<pthread.h> 

int contor; 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void *incrementare(void *args) { 
    intptr_t id = (intptr_t)args; // proper way to pass an integer via thread param 
    while(1) { 
     pthread_mutex_lock(&mutex); 
     if (contor >= 100) { 
      pthread_cond_broadcast(&cond); 
      pthread_mutex_unlock(&mutex); 
      pthread_exit(NULL); 
     } 

     while (contor %3 != id) { 
     pthread_cond_wait(&cond,&mutex); 
     } 

     contor++; 
     printf("Thread %"PRIdPTR " increment: %d\n",id,contor); 


     pthread_cond_broadcast(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 
    return NULL; // should always have well-defined return value 
} 

int main(void) { 
    pthread_t th1, th2,th3; 

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) { 
     perror("Error!\n"); 
     exit(1); 
    } 
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) { 
     perror("Error!\n"); 
     exit(2); 
    } 
    if(pthread_create(&th3, NULL, &incrementare, (void *)2) < 0) { 
     perror("Error!\n"); 
     exit(3); 
    } 

    pthread_join(th1, NULL); 
    pthread_join(th2, NULL); 
    pthread_join(th3, NULL); 

    pthread_mutex_destroy(&mutex); 
    pthread_cond_destroy(&cond); 

    return 0; 
} 

結果如下:

Thread 0 increment: 1 
Thread 1 increment: 2 
Thread 2 increment: 3 
Thread 0 increment: 4 
Thread 1 increment: 5 
Thread 2 increment: 6 
Thread 0 increment: 7 
Thread 1 increment: 8 
Thread 2 increment: 9 
Thread 0 increment: 10 
.... 
Thread 0 increment: 97 
Thread 1 increment: 98 
Thread 2 increment: 99 
Thread 0 increment: 100 
Thread 1 increment: 101 
Thread 2 increment: 102 

See it live

額外的兩個輸出是因爲代碼檢查的天花板中斷條件爲之前的 cvar-predicate循環。在之後應該是,但是我留給你解決。

但請記住,這樣做最終會失去在任務上鬆動多個線程的目的。理想情況下,您希望任何線程可用於執行工作以實際執行此操作。你的工作隻影響一個單一的全局,但卻有損於線程的真正目的(顯然你不會使用線程數到100;循環中的單個線程是理想的)。


無論如何,您的程序的精簡版本如下所示。更改N_THREADSN_COUNT的值以查看輸出的差異。

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <inttypes.h> 
#include <pthread.h> 

#define N_THREADS 7 
#define N_COUNT 100 

int contor; // 0 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void *incrementare(void *args) 
{ 
    intptr_t id = (intptr_t)args; 
    pthread_mutex_lock(&mutex); 
    while(1) 
    { 
     while (contor < N_COUNT && contor % N_THREADS != id) 
      pthread_cond_wait(&cond, &mutex); 

     if (contor == N_COUNT) 
      break; 

     printf("Thread %"PRIdPTR" increment: %d\n", id, ++contor); 
     pthread_cond_broadcast(&cond); 
    } 
    pthread_mutex_unlock(&mutex); 
    return NULL; 
} 

int main(void) 
{ 
    pthread_t ar[N_THREADS]; 
    intptr_t id = 0; 

    for (int i=0; i<N_THREADS; ++i) 
    { 
     if(pthread_create(ar+i, NULL, &incrementare, (void *)id++) < 0) { 
      perror("Error!\n"); 
      exit(1); 
     } 
    } 

    for (int i=0; i<N_THREADS; ++i) 
     pthread_join(ar[i], NULL); 

    return 0; 
} 
+0

嘿,我試過你的第一個解決方案,但它沒有工作。它給線程0增量:1然後停止,實際上它什麼都不做,以某種方式停留在無限循環中。 –

+0

@HopelessWanderer是的,我忽略提到需要將您的信號更改爲廣播。原因很重要。閱讀更新的答案。 – WhozCraig

+0

非常感謝!它現在工作! :d –

相關問題