2012-07-05 33 views
0

我在設計具有線程池的程序時遇到了問題。使用C++中的pthreads實現的線程池

我堅持的主要問題是當一個線程完成工作父母必須等待threadId(這是一個父母如何使用pthread_join等待線程)。因爲我們不知道哪個線程將首先完成,所以我無法找出解決問題的編程方式。

任何解釋與一小段代碼表示讚賞。

謝謝。

+0

你是在實現一個線程池還是一些線程,每個線程都需要完成某個部分的問題?如果是後者,那麼首先完成並不重要:您可以依次等待每個線程,因爲即使第一個線程最後完成,其他線程也會在您等待時完成。 – craigmj 2012-07-05 10:24:43

回答

0

如果你想實現一個線程池,看看我幾年前玩過的這個架構。我已經寫它在這裏:Thread Pooling in C++

對於非阻塞在pthread_join,請參閱本SO討論:Non-blocking pthread_join

如果你只是等待所有的線程來完成他們的工作,你可以等待他們一個接一個:訂單無關緊要,沒有理由使用條件。這個例子表明:

#include <memory.h> 
#include <pthread.h> 

#include <iostream> 

using namespace std; 

#define NTHREADS 10 

void *thread(void *arg) { 
    int *n = (int *) arg; 
    sleep(10 - *n); 
    cout << "Thread " << (*n) << endl; 
    delete n; 
    return NULL; 
} 

int main(int argc, char **argv) { 
    pthread_t threads[NTHREADS]; 
    pthread_attr_t attr; 
    memset(&attr, 0, sizeof(attr)); 
    int i; 
    for (i=0; i<NTHREADS; i++) { 
     int *p = new int; 
     *p = i; 
     pthread_create(threads + i, &attr, thread, p); 
    } 
    void *rval; 
    for (i=0; i<NTHREADS; i++) { 
     pthread_join(threads[i], &rval); 
     cout << "Joined thread " << i << endl; 
    } 
    return 0; 
} 

雖然線程的順序相反的順序,以等待完成時(即線程0完成最後的,但我們等待的線程0第一),主線程將不會退出,直到所有的線程完成。沒有條件要求。


1

好了,我不知道你的設置和要求,但你遇到了那個在pthread_join()等待正是一個線程的問題,你真正希望等待任何線程。

因此,最明顯的結論是pthread_join不能幫助你。對不起,說明明顯,但我需要建立我的情況:-)

相反,你可能不得不想出另一個想法。例如,你可以等待一個條件變量;在線程退出之前它會將條件設置爲「退出」。主線程可以等待這種情況,遍歷線程以找出哪些線程已經終止(可以是多個線程),並最終重置條件。互斥狀態通常足以阻止比賽。

除了設置條件(可以使用條件互斥鎖來保護該列表)之外,線程還可以將一些ID添加到已退出的線程列表中,因此主線程只需要通過該列表而不是檢查每個線。

僞代碼:

initialize condition variable with status "not exited" 
... 
... 
launch your threads 
... 
... 
while (some threads are still running) do 
    lock condition variable on "exited" 
    iterate through threads, remove the ones that have exited 
    unlock condition variable with new condition "not exited" 

你的線程裏面:

... 
do whatever it needs to do 
... 
... 
lock condition variable 
unlock condition variable with new condition "exited" 
/* end of thread */ 
+1

+1僅僅用於dising join(),不過也許我應該再次關閉它,以獲得包含「遍歷線程以找出哪些已終止的答案」的答案:) – 2012-07-05 20:14:37

1

池通常爲一些等待任務物品生產者 - 消費者隊列的線程來實現。任務是派生自具有'run()'方法的Task類的對象。無論哪個線程獲得任務,它都會調用run(),並且當線程返回時,線程循環以從隊列中獲取另一個任務對象。

這吹掉了任何線程微觀管理,並且在我嘗試過的每個系統/語言上都可靠和安全地工作。

我知道完成通知的最靈活的方法是當run()返回時,線程調用一個'OnComplete'事件或可能是一個虛擬的'completed'方法,在循環返回以獲取下一個任務,將任務作爲參數。例如,這個方法/事件可以指示任務發起線程正在等待的事件/ condvar/sema,可以將完成的任務排隊到發起線程或另一個線程,或者甚至只是刪除()任務(可能它是作業完全在線程池中完成)。

對於錯誤通知,我會捕獲run()拋出的任何未捕獲的異常,並在調用completion方法/事件之前將異常存儲在tast字段中。

除了那些保護生產者 - 消費者隊列的鎖之外,沒有鎖(並且它們只需要足夠長的時間來推送/彈出*任務)。

無論使用哪種設計,請,請儘量很難不:

1) continually create/terminate/destroy threads - avoidable overhead and tricky to manage 
2) wait with Join() for any thread to terminate - just don't :) 
3) loop around some 'poll thread status' to see if they're finished yet - gets it wrong 
4) Move 'working/finished' threads into and out of containers with complicated locks - deadlock-in-the-making 
5) use any other sort of micro-management - difficult, messy, error-prone, too many locks, unnecesary, avoidable 

理想的線程池,你不知道哪個線程所做的工作。事實上,通常不需要保留對線程的任何引用。雙線僞線程池:

TblockingQueue *inQueue=new TblockingQueue(); 
for(int i=0;i<CpoolDepth,i++) new Thread(inQueue);