我有一个带有虚拟方法的IT课程:
class ITask
{
public:
virtual void Execute() = 0;
};
我创建了一个系统,可以在不同的线程上分配任务,使它们并行执行。事情是,我需要一些任务在某些其他任务完成之前无法执行。单个任务可以依赖于多个任务父任务,所以我不能做这样的事情:
void Task::Execute()
{
//do stuff
//finished
for(int i = 0; i < children.size(); i++)
{
ThreadingSystem::QueuedTasks.push_back(children[i]);
}
}
所以我做了类似的事情:
class Task : public ITask
{
public:
void Execute();
unsigned int dependency;
vector<Task*> children;
};
void Task :: Execute() { //做东西 //结束
for(int i = 0; i < children.size(); i++)
{
children[i]->dependency--;
}
}
所以基本上这种方式只有具有0U依赖关系的任务可以自由执行,所以一个任务需要等待所有父项完成才能执行。现在问题是,这个系统变得非常混乱,例如:
for(int i = 0; i < children.size(); i++)
{
if(children[i]->dependency == 0U)
{
ThreadingSystem::QueuedTasks.push_back(children[i]);
//either remove added task from children or set a flag in it to mark as "queued"
}
}
我必须基本上不停地调用这个直到所有的孩子都没有向量。第一次迭代可能只发送2个任务到多线程队列,第二次迭代可能发送另外3个,第三次迭代发送另外7个,等等它完全不可预测,并且涉及很多分支和循环。也许关于依赖整数的整个想法都很糟糕?
答案 0 :(得分:1)
dependencies
。
child->AddDependency
和child->SatisfyDependency
。child->SatisfyDependency
应将子项添加到队列中。如果你能找到一个,你应该考虑引入一个已经调试过的基于任务的线程池库。
答案 1 :(得分:1)
您可以根据要执行的原始任务构建依赖关系树。假设您要执行TaskA,它依赖于TaskB和TaskC。 TaskC本身依赖于TaskD。
让你的任务保存他们的孩子,这是他们的依赖!
class Task : public ITask
{
public:
void Execute();
vector<Task*> children;
};
对于TaskA,向量 children 将由TaskB和TaskC组成。 TaskB没有其他子任务。 TaskC有子TaskD。
ThreadingSystem中的线程将解析Task树(从TaskA开始)并搜索一个叶子,即没有子节点的Task。如果一个线程找到一个叶子,它将确保没有其他线程可以同时运行该任务。旗帜可能有用。
执行后,将从树中删除叶子并搜索另一片叶子。
如果当前没有可用的叶子,则线程必须等到一个可用。只要叶子被执行,你就可以将它们唤醒。
当没有任务离开时,即从树中删除TaskA时,执行ThreadingSystem。您可以发送一个事件或取消阻止调用者或其他东西。
当您评论答案时,您这样做是出于教育目的。尝试实现一个树,如果你完成了,你可以尝试实现(定向)图。或者实施循环检测。尝试加快查找/缓存叶子等的性能。
或者......使用现有框架。 ;)