我有std :: list< Info>我的应用程序中的infoList在两个线程之间共享.这两个线程正在访问此列表,如下所示:
线程1:在列表上使用push_back(),pop_front()或clear()(视情况而定)
线程2:使用迭代器遍历列表中的项目并执行一些操作.
线程2正在迭代列表,如下所示:
for(std::list<Info>::iterator i = infoList.begin(); i != infoList.end(); ++i) { DoAction(i); }
代码是使用GCC 4.4.2编译的.
有时我会导致segfault并且崩溃应用程序.错误是在std_list.h第143行引起的,如下所示:
_M_node = _M_node->_M_next;
我猜这是一个赛车条件.线程2正在迭代时,该列表可能已更改或甚至被线程1清除.
我使用Mutex来同步访问这个列表,并且在我的初始测试期间,所有的都进行了.但系统在压力测试下冻结,使得该解决方案完全不可接受.该应用程序是一个实时应用程序,我需要找到一个解决方案,这样两个线程可以尽可能快地运行,而不会影响总应用程序吞吐量.
我的问题是这样的:
线程1和线程2需要尽可能快地执行,因为这是一个实时应用程序.我可以做什么来防止这个问题,仍然保持应用程序的性能?有没有免费的算法可用于这样的问题?
如果我在线程2的迭代中错过了一些新添加的Info对象,那么它可以,但是我可以做什么来防止迭代器成为悬挂指针?
谢谢
解决方法
一般来说,以这种方式使用STL容器是不安全的.您将必须实现特定的方法,使您的代码线程安全.您选择的解决方案取决于您的需求.我可能通过维护两个列表来解决这个问题,每个列表中有一个.并通过
lock free queue(在评论中提到这个问题)传达变化.您也可以通过将它们包装在boost :: shared_ptr中来限制Info对象的生命周期.
typedef boost::shared_ptr<Info> InfoReference; typedef std::list<InfoReference> InfoList; enum CommandValue { Insert,Delete } struct Command { CommandValue operation; InfoReference reference; } typedef LockFreeQueue<Command> CommandQueue; class Thread1 { Thread1(CommandQueue queue) : m_commands(queue) {} void run() { while (!finished) { //Process Items and use // deleteInfo() or addInfo() }; } void deleteInfo(InfoReference reference) { Command command; command.operation = Delete; command.reference = reference; m_commands.produce(command); } void addInfo(InfoReference reference) { Command command; command.operation = Insert; command.reference = reference; m_commands.produce(command); } } private: CommandQueue& m_commands; InfoList m_infoList; } class Thread2 { Thread2(CommandQueue queue) : m_commands(queue) {} void run() { while(!finished) { processQueue(); processList(); } } void processQueue() { Command command; while (m_commands.consume(command)) { switch(command.operation) { case Insert: m_infoList.push_back(command.reference); break; case Delete: m_infoList.remove(command.reference); break; } } } void processList() { // Iterate over m_infoList } private: CommandQueue& m_commands; InfoList m_infoList; } void main() { CommandQueue commands; Thread1 thread1(commands); Thread2 thread2(commands); thread1.start(); thread2.start(); waitforTermination(); }
这还没有编译.您仍然需要确保对Info对象的访问是线程安全的.