您想要的概念是线程池。这个SO question处理现有的实现。
这个想法是为许多线程实例提供一个容器。每个实例都与一个轮询任务队列的函数相关联,当任务可用时,拉取并运行它。一旦任务结束(如果它终止,但这是另一个问题),线程简单地循环到任务队列。
所以你需要一个同步队列,一个实现队列循环的线程类,一个任务对象的接口,也许还有一个驱动整个事物的类(池类)。
或者,您可以为其必须执行的任务创建一个非常专业的线程类(例如,仅将内存区域作为参数)。这需要线程的通知机制来指示它们已完成当前迭代。
线程主函数将是该特定任务的循环,并且在一次迭代结束时,线程发出结束信号,并等待条件变量开始下一个循环。本质上,您将在线程中内联任务代码,完全不需要队列。
using namespace std;
// semaphore class based on C++11 features
class semaphore {
private:
mutex mMutex;
condition_variable v;
int mV;
public:
semaphore(int v): mV(v){}
void signal(int count=1){
unique_lock lock(mMutex);
mV+=count;
if (mV > 0) mCond.notify_all();
}
void wait(int count = 1){
unique_lock lock(mMutex);
mV-= count;
while (mV < 0)
mCond.wait(lock);
}
};
template <typename Task>
class TaskThread {
thread mThread;
Task *mTask;
semaphore *mSemStarting, *mSemFinished;
volatile bool mRunning;
public:
TaskThread(Task *task, semaphore *start, semaphore *finish):
mTask(task), mRunning(true),
mSemStart(start), mSemFinished(finish),
mThread(&TaskThread<Task>::psrun){}
~TaskThread(){ mThread.join(); }
void run(){
do {
(*mTask)();
mSemFinished->signal();
mSemStart->wait();
} while (mRunning);
}
void finish() { // end the thread after the current loop
mRunning = false;
}
private:
static void psrun(TaskThread<Task> *self){ self->run();}
};
classcMyTask {
public:
MyTask(){}
void operator()(){
// some code here
}
};
int main(){
MyTask task1;
MyTask task2;
semaphore start(2), finished(0);
TaskThread<MyTask> t1(&task1, &start, &finished);
TaskThread<MyTask> t2(&task2, &start, &finished);
for (int i = 0; i < 10; i++){
finished.wait(2);
start.signal(2);
}
t1.finish();
t2.finish();
}
上面提出的(粗略)实现依赖于Task
必须提供的类型operator()
(即类仿函数)。之前说过可以将任务代码直接合并到线程函数体中,但由于我不知道,所以我尽量保持抽象。线程开始有一个条件变量,线程结束有一个条件变量,两者都封装在信号量实例中。
看到另一个建议使用的答案 boost::barrier
,我只能支持这个想法:如果可能,请确保用该类替换我的信号量类,原因是最好依赖经过良好测试和维护的外部代码而不是自我实现相同功能集的解决方案。
总而言之,这两种方法都是有效的,但前者为了灵活性而放弃了一点点性能。如果要执行的任务需要足够长的时间,则管理和队列同步成本可以忽略不计。
更新:代码已修复和测试。用信号量替换了一个简单的条件变量。