2013-07-20 27 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:糟糕 - 纠正。谢谢。 –