0

我在设计具有线程池的程序时遇到了麻烦。

我遇到的主要问题是当一个线程完成工作时,父级必须等待threadId(这是父级使用pthread_join等待线程的方式)。因为我们不知道哪个线程将首先完成,所以我无法找出解决问题的编程方法。

任何带有一小段代码的解释都值得赞赏。

谢谢。

4

3 回答 3

1

池通常实现为在生产者-消费者队列中等待任务项的多个线程。任务是派生自具有“run()”方法的任务类的对象。无论哪个线程获得一个任务,它都会调用 run(),当它返回时,线程循环以从队列中获取另一个任务对象。

这消除了任何线程微管理,并且可以在我尝试过的每种系统/语言上可靠且安全地工作。

我知道的完成通知最灵活的方法是线程在 run() 返回时调用任务的“OnComplete”事件,或者可能是虚拟的“完成”方法,就在循环返回以获取下一个任务之前,使用任务作为参数。例如,此方法/事件可以发出一个事件/condvar/sema 信号,任务发起线程正在等待该事件/condvar/sema,可以将已完成的任务排队到发起线程或另一个线程,甚至只是 delete() 任务,(也许它是作业完全在线程池中完成)。

对于错误通知,我捕获 run() 抛出的任何未捕获的异常,并将异常存储在 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);
于 2012-07-05T20:04:25.127 回答
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 */
于 2012-07-05T10:34:37.677 回答
0

如果你想实现一个线程池,看看我几年前玩过的这个架构。我在这里写了:C++ 中的线程池

对于非阻塞 pthread_join,请参阅此 SO 讨论:非阻塞 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),但直到所有线程都完成后,主线程才会退出。不需要条件。


于 2012-07-05T10:34:20.843 回答