如何避免基于任务的程序的递归任务列表遍历?

时间:2013-12-05 20:41:18

标签: multithreading algorithm scheduled-tasks

我有一个带有虚拟方法的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个,等等它完全不可预测,并且涉及很多分支和循环。也许关于依赖整数的整个想法都很糟糕?

2 个答案:

答案 0 :(得分:1)

  • 使用getter / setter而不是直接访问dependencies
    • 类似于child->AddDependencychild->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。您可以发送一个事件或取消阻止调用者或其他东西。

注意

当您评论答案时,您这样做是出于教育目的。尝试实现一个树,如果你完成了,你可以尝试实现(定向)图。或者实施循环检测。尝试加快查找/缓存叶子等的性能。

或者......使用现有框架。 ;)