2012-07-05 34 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);