2013-12-17 39 views
1

我有一組數據,其中包含對這些數據進行操作的「代理」。我還在代理之間建立了一個依賴列表,因爲一些代理依賴於其他代理執行的操作。我還設置了一個結構來強制每個代理可以訪問或變更數據集合中的數據。我被困在如何實現這個設計上,作業池似乎太簡單了,無法處理依賴關係。我的問題與如何實際實現這種類型的設計有關。該設計與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()循環中運行。

+0

我們在談論多少個代理商?一個天真的解決方案是,依賴關係只是'std :: future's,而依賴關係只是''代理'線程對其每個輸入做'wait'。 – Yakk

+0

如果號碼太高,代理的功能可以結合使用。但是現在我已經將最大值設置爲256,並且我當前使用了24.有11個沒有依賴關係。 – h4tch

回答

0

您有一個封裝數據的對象,以及處理這些數據的代理,它們一起是訪客設計模式的基礎。根據四人幫,訪客模式的意圖是

表示要對對象/結構的元素執行的操作。訪問者可以讓你定義一個新的操作而不需要改變它所操作的元素的類。

抽象基訪問者,訪問類將至少有以下功能:

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; 
}; 

對於要建立責任鏈,使用調解員將是一個良好的開端 - 意圖:

定義一個封裝一組對象如何交互的對象。中介承諾通過保持對象明確互相引用來鬆散耦合,並且它可以讓你獨立地改變它們的交互。

爲此,我們至少要修改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. 定義私有的std ::互斥,std :: condition_variable,可能還有一個線程安全隊列;
  2. 在CreateVisitors()中,將a1,a2,a3,a4推送到visitors_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(& ConcreteMediator :: a1_thread,this); ... threadv.emplace_back(& ConcreteMediator :: a4_thread,this); std :: for_each(threadv.begin(),threadv.end(),std :: mem_fn(& std :: thread :: join));

這是一個相當不古板的設置,但它確實保持了您所期望的鬆耦合(中介者)和可擴展性(訪問者)。

相關問題