2011-12-13 59 views
1

我有10個線程應該等待信號。 到目前爲止,我只是做了'睡眠(3)',這一直工作正常,但是有一種更安全的方式來確保所有線程都已創建並且確實在等待。確保創建線程並在廣播前等待

我做了以下建設,我在臨界區域,在等待之前,增加一個計數器,告訴有多少線程在等待。但是接下來我必須有一個額外的互斥鎖,並且有條件地向所有線程創建的主要信號發送,看起來過於複雜。

我是否缺少一些基本的線程設計模式?

感謝 編輯:固定類型

編輯:澄清如下

信息的壁壘不會在這種情況下工作,因爲我不感興趣,讓我的線程等待,直到所有線程都準備好了。這已經發生在'cond_wait'。

我感興趣的是在所有線程都準備好並等待時讓主函數知道。

//mutex and conditional to signal from main to threads to do work 
mutex_t mutex_for_cond; 
condt_t cond; 

//mutex and conditional to signal back from thread to main that threads are ready 
mutex_t mutex_for_back_cond; 
condt_t back_cond; 

int nThreads=0;//threadsafe by using mutex_for_cond 

void *thread(){ 
    mutex_lock(mutex_for_cond); 
    nThreads++; 
    if(nThreads==10){ 
     mutex_lock(mutex_for_back_cond) 
     cond_signal(back_cond); 
     mutex_unlock(mutex_for_back_cond) 
    }while(1){ 
     cond_wait(cond,mutext_for_cond); 
     if(spurious) 
     continue; 
     else 
     break; 
    } 
    mutex_unlock(mutex_for_cond); 
    //do work on non critical region data 
} 

int main(){ 
for(int i=0;i<10) 
    create_threads; 

while(1){ 
    mutex_lock(mutex_for_back_cond); 
    cond_wait(back_cond,mutex_for_back_cond); 
    mutex_unlock(mutex_for_back_cond); 
    mutex_lock(mutex_for_cond); 
    if(nThreads==10){ 
    break; 
    }else{ 
    //spurious wakeup 
    mutex_unlock(mutex_for_cond); 
    } 
} 
//now all threads are waiting 
//mutex_for_cond is still locked so broadcast 
cond_broadcast(cond);//was type here 


} 
+0

您在這裏出現的版本已經是越野車了。 (1)你正在閱讀`nThreads`而沒有鎖定。 (2)如果出現「虛假喚醒」,您將解鎖互斥鎖兩次。 – 2011-12-13 23:12:02

+0

而你的客戶端也鎖定兩次。也許你試圖在你嘗試引入進一步的複雜性之前嘗試獲取現有的代碼。 – 2011-12-13 23:13:35

回答

3

我缺少一些基本的線程設計模式?

是的。對於每種情況,都應該有一個受相關互斥鎖保護的變量。只有條件變量上的信號指示此變量的更改。

您檢查在一個循環的變量,等待條件:

mutex_lock(mutex_for_back_cond); 
while (ready_threads < 10) 
    cond_wait(back_cond,mutex_for_back_cond); 
mutex_unlock(mutex_for_back_cond); 

此外,你正在試圖建立一個線程屏障。它通常在線程庫中預先實現,如pthread_barrier_wait

2

明智的線程API有一個barrier構造,正是這樣做。

例如,boost::thread,您可以創建這樣一個障礙:

boost::barrier bar(10); // a barrier for 10 threads 

,然後每個線程將等待的障礙:

bar.wait(); 

屏障等待,直到指定數量的線程正在等待它,然後一次釋放它們。換句話說,一旦所有十個線程都已經創建並準備就緒,它將允許它們全部繼續。

這就是簡單而健全的做法。沒有屏障構造的線程化API需要你以艱難的方式來完成,與你現在正在做的不同。

0

您應該將一些包含'event state'的變量與條件變量關聯起來。主線程在發佈廣播之前恰當地設置事件狀態變量。對事件感興趣的線程檢查事件狀態變量,而不管它們是否阻塞了條件變量。

使用這種模式,主線程不需要知道線程的準確狀態 - 它只是在需要時才設置事件,然後廣播條件。任何等待的線程都將被解除阻塞,並且任何未等待的線程都不會在條件變量上阻塞,因爲他們會注意到該事件在等待條件之前已經發生。像下面的僞代碼:

//mutex and conditional to signal from main to threads to do work 
pthread_mutex_t mutex_for_cond; 
pthread_cond_t cond; 
int event_occurred = 0; 

void *thread() 
{ 
    pthread_mutex_lock(&mutex_for_cond); 
    while (!event_occurred) { 
      pthread_cond_wait(&cond, &mutex_for_cond); 
    } 
    pthread_mutex_unlock(&mutex_for_cond); 

    //do work on non critical region data 
} 

int main() 
{ 
    pthread_mutex_init(&mutex_for_cond, ...); 
    pthread_cond_init(&cond, ...); 

    for(int i=0;i<10) 
     create_threads(...); 

    // do whatever needs to done to set up the work for the threads 

    // now let the threads know they can do their work (whether or not 
    // they've gotten to the "wait point" yet) 
    pthread_mutex_lock(&mutex_for_cond); 
    event_occured = 1; 
    pthread_cond_broadcast(&cond); 
    pthread_mutex_unlock(&mutex_for_cond); 
}