2013-07-20 31 views
0

我有一個模擬程序。在模擬的主要類中,我正在「創建+添加」和「刪除+銷燬」代理。在運行時添加和刪除列表

問題是,有一次(每3-4次運行一次程序)程序崩潰,因爲我顯然在主循環中調用無效代理的函數。該程序在大多數時間工作得很好。列表中通常有數千個代理。

  • 我不知道我的循環中有無效代理的可能性如何。
  • 調試代碼非常困難,因爲我在「Agent :: Step函數」內部收到內存異常(這太遲了,因爲我無法理解列表中的無效代理是如何調用的)。

    當我查看Agent :: Step函數內的代理引用(異常點)時,代理中的數據沒有意義,甚至沒有初始化數據。所以這絕對是無效的。

    void World::step() 
    { 
        AddDemand(); 
    
        // run over all the agents and check whether they have remaining actions 
        // Call their step function if they have, otherwise remove them from space and memory 
        list<Agent*>::iterator it = agents_.begin(); 
        while (it != agents_.end()) 
        { 
         if (!(*it)->AllIntentionsFinished()) 
         { 
          (*it)->step(); 
          it++; 
         } 
         else 
         { 
          (*it)->removeYourselfFromSpace(); //removes its reference from the space 
          delete (*it); 
          agents_.erase(it++); 
         } 
        } 
    } 
    
    void World::AddDemand() 
    { 
        int demand = demandIdentifier_.getDemandLevel(stepCounter_); 
        for (int i = 0; i < demand; i++) 
        { 
         Agent* tmp = new Agent(*this); 
         agents_.push_back(tmp); 
        } 
    } 
    
    Agent: 
    
    bool Agent::AllIntentionsFinished() 
    { 
        return this->allIntentionsFinished_; //bool flag will be true if all work is done 
    } 
    

1-難道循環(即在多線程,如果可能的運行)的VStudio 2012優化造成的問題?

2-關於調試代碼的任何建議?

回答

0

問題是這樣的:

agents_.erase(it++); 

Add and remove from a list in runtime

我沒有看到你表現出任何代碼線程安全的成分,因此,如果您運行的是它們之間的多線程和共享數據,那麼絕對可以有一個線程問題。例如,您這樣做:

(*it)->removeYourselfFromSpace(); //removes its reference from the space 
delete (*it); 
agents_.erase(it++); 

這是未鎖定列表中可能出現的最差順序。您應該:從列表中刪除,按照該順序刪除對象,刪除對象。

但是,如果您不是專門創建共享列表/代理的線程,那麼線程可能不是您的問題。

+0

謝謝。它是否也適用於列表(因爲我使用列表而不是矢量)。 我不使用線程,但我認爲vstudio 2012編譯器嘗試使用線程(如果它認爲可以)。 – wmac

+0

呃,是的 - 抱歉,那是錯誤的鏈接 - 它實際上是我嘗試鏈接的頁面引用的位置,但鏈接到列表頁面會更有意義:) – kfsone

+0

更改順序並未解決問題。使用「it = agents_erase(it);」也沒有解決問題。我想我應該再仔細看看我的所有代碼。你的鏈接也指向同樣的問題btw。 – wmac

2

如果您正在使用多線程代碼,那麼您需要添加代碼來保護添加項目以及從列表中刪除項目等內容。你可以創建一個包裝器,它可以相當容易地爲容器添加線程安全性 - 只要你在底層容器上進行可能的修改操作時就擁有一個互斥鎖。

template <class Container> 
thread_safe { 
    Container c; 
    std::mutex m; 
public: 
    void push_back(typename Container::value_type const &t) { 
     std::lock_guard l(m); 
     c.push_back(t); 
    } 
    // ... 
}; 

其他一些要點:

  1. 您可以通過具有單持有Agent小號直接,而不是一個指針,你必須代理幾乎可以肯定清理你的代碼佔用相當多的動態分配。

  2. 您的Agent::RemoveYourselfFromSpace看起來/聽起來很像是應該由代理的析構函數處理的東西。

  3. 通過使用某些標準算法,您幾乎可以肯定會做更多的清理代碼。

例如,它看起來對我來說,你的step可以寫成這樣:

agents.remove_if([](Agent const &a) { return a.AllIntentionsFinished(); }); 

std::for_each(agents.begin(), agents.end(), 
       [](Agent &a) { a.step(); }); 

...或者,你可能更願意繼續使用一個明確的循環,但使用這樣的:

for (Agent & a : agents) 
    a.step(); 
+0

感謝您的評論。 Agent :: RemoveYourselfFromSpace僅從名爲空間的數組中刪除代理引用(以便它不出現在空間中)。它不會觸及其他任何東西。 我有數百個類,使用代理的指針可以更容易地避免類之間的鏈獨立性。 感謝您的其他建議。 – wmac

+0

@Jerry Coffin你的意思是「std :: lock」或「std :: lock_guard 」?我認爲std :: lock是[函數](http://en.cppreference.com/w/cpp/thread/lock)。 – kfsone

+0

@kfsone:糟糕 - 糾正。謝謝。 –