假设我有一个N个元素的向量,但该向量的n个元素具有有意义的数据。一个更新程序线程更新第n个或第n + 1个元素(然后设置n = n + 1),还检查n是否太接近N并在必要时调用vector :: resize(N + M)。更新后,线程调用多个子线程来读取第n个数据并进行一些计算。
保证子线程永远不会更改或删除数据(实际上没有数据被删除),updater在完成更新后会调用它们。
到目前为止还没有出现任何问题,但是我想询问在将向量重新分配给更大的内存块时是否可能出现问题,如果前一次更新中还有一些子工作线程。
或者在这样的多线程情况下使用向量是否安全,因为它不是线程安全的?
编辑: 由于只有在updater调用vector :: resize(N + M,0)时才进行插入,我的问题是否有任何可能的解决方案?由于STL向量的强大性能,我不愿意用可锁定的向量替换它,或者在这种情况下是否有任何高性能,已知和无锁的向量?
答案 0 :(得分:20)
我想询问在将向量重新分配给更大的内存块时是否可能出现问题,如果上一次更新中还有一些子工作线程。
是的,这会非常糟糕。
如果您正在使用来自多个线程的容器,并且至少有一个线程可能会执行某些可能会修改容器状态的操作,则必须同步对容器的访问。
在std::vector
的情况下,任何改变其大小(特别是插入和删除)的内容都会改变其状态,即使不需要重新分配(任何插入或擦除都需要std::vector
的内部要更新的大小簿记数据。)
问题的一个解决方案是让生产者动态分配std::vector
并使用std::shared_ptr<std::vector<T> >
拥有它并将此std::shared_ptr
提供给每个消费者。
当生产者需要添加更多数据时,它可以动态地分配一个新的std::vector
,其中包含新的,更大的大小以及旧std::vector
中元素的副本。然后,当您分拆新消费者或使用新数据更新消费者时,您只需向新std::shared_ptr
提供std::vector
。
答案 1 :(得分:1)
您的员工是如何决定安全地保护数据线程的?工人和制片人之间是否有任何信号?如果没有,那么肯定存在一个问题,即生产者可能会导致向量在仍然处于工作状态时移动。虽然可以通过移动到std::deque
来解决这个问题。(注意std::deque
使push_back
上的迭代器无效,但对元素的引用不受影响。
答案 2 :(得分:0)
我已经制作了自己的GrowVector。它对我有用,而且非常快。