具有依赖关系的作业池的设计和实现

时间:2013-12-17 20:44:03

标签: c++11 promise future channel

我有一组数据,其中“代理”对该数据进行操作。我还在代理之间建立了一个依赖列表,因为一些代理依赖于其他代理所做的事情。我还设置了一个结构来强制执行每个代理可以访问或变更数据集合中的数据。我坚持如何实现这个设计,工作池似乎太简单,无法处理依赖项。我的问题与如何实际实现这种类型的设计有关。该设计与FlowBased编程非常相似(如果我理解正确的话),但数据是批量操作的。

我的第一个想法是要完成需要完成的任务的树状结构:

    Root
   /  |  \
 a1   a2  a3
  | /
 a4

例如,我可以同时运行a1,a2和a3。但要运行a4,a1和a2需要完成。

设置此功能的最佳工具是什么?我应该使用信号/插槽实现,滚动我自己的频道,使用期货和承诺模拟频道/信号/插槽系统?也许使每个节点具有许多依赖关系,并且当每个依赖代理完成时,计数器在调用下一个节点时递增,直到它与deps的数量匹配。或者这可以实现为“门”类型的结构,其保持deps的数量并在满足deps时向代理发送信号或w / e。 我可以创建自己的TaskManager来执行调度,但我宁愿调用每个顶级节点一次,并自动遍历层次结构。完全是我可以尝试的其他东西。我对你可能有的任何疯狂想法感兴趣。

我倾向于这样的事情,使用“信号”和“插槽”:

+----------+    +----------+
|  Actor1  |    |  Actor2  |
| update() |    | update() |
+----|-----+    +----|-----+
      \____    _____/
           \  /   
         +---v---+
         |  Gate |
         +---|---+
             V
        +----------+
        |  Actor4  |
        | update() |
        +----------+

这种问题通常是如何解决的?如果可以的话,我想保持它有点通用并使用流行的库。我还需要良好的响应时间,因为它将在游戏引擎的update()循环中运行。

1 个答案:

答案 0 :(得分:0)

您有一个封装数据的对象,以及处理该数据的代理,它们共同构成了访问者设计模式的基础。根据Gang of Four的说法,访客模式的意图是

  

表示要对对象/结构的元素执行的操作。访问者允许您定义新操作,而无需更改其操作的元素的类。

抽象基本访问者,访问过的类至少具有以下功能:

class DataElement
{
 public:
   virtual ~DataElement() = default;
   virtual void Accept(DataVisitor*);
 protected:
   DataElement() = default;
};

DataElement::Accept(DataVisitor* v)
{
    v->gendata(this); // double dispatch
}

class DataVisitor
{
 public:
   virtual ~DataVisitor() {} = default;
   virtual void visit_SpreadData(SpreadData*) = 0;   
   virtual void gendata(DataElement*) = 0;
 protected:
   DataVisitor() = default;
};

对于您正在设立的责任链,使用调解员将是一个良好的开端 - 意图:

  

定义一个封装一组对象如何交互的对象。 mediator通过保持对象明确地相互引用来承诺松散耦合,并且它允许您独立地改变它们的交互。

为此,我们至少会修改DataVisitor类以包含私有中介类。抽象介体基类可能类似于:

class Mediator
{
 public:
   virtual ~Mediator() = default;
   virtual void mediate() = 0;
   std::list<DataVisitor*> get_visitors() const
 protected:
   Mediator() = default;
   virtual void CreateVisitors() = 0;
   std::list<DataVisitor*> visitors_;
};

在具体的介体类中,指定图中行为的类,主要成分是:

  1. 定义private std :: mutex,std :: condition_variable,可能还有一个线程安全队列;
  2. 在CreateVisitors()中,将a1,a2,a3,a4推送到visitor_ list;
  3. 为每个a_i创建线程方法,a1_thread(),a2_thread(),a3_thread()将立即运行,而a4_thread()将等待a1,a2的完成,可能使用gendata()的结果(通过notify_one ())已被推入队列;
  4. 填写mediate(): std :: vector threadv; threadv.emplace_back(&amp; ConcreteMediator :: a1_thread,this); ... threadv.emplace_back(&amp; ConcreteMediator :: a4_thread,this); std :: for_each(threadv.begin(),threadv.end(),std :: mem_fn(&amp; std :: thread :: join));
  5. 这是一个非常简单的设置,但它确实维护了你想要的松耦合(Mediator)和可扩展性(Visitor)。

相关问题