2010-12-03 86 views
11

假设我有一个由N个元素组成的向量,但是这个向量中多达n个元素具有有意义的数据。一个更新程序线程更新第n个或第n + 1个元素(然后设置n = n + 1),还检查n是否太接近于N,并在必要时调用vector :: resize(N + M)。更新后,线程调用多个子线程读取第n个数据并进行一些计算。STL向量和线程安全

确保子线程永远不会更改或删除数据(实际上没有数据被删除,所以永远不会删除数据),更新程序在完成更新后立即调用子线程。

到目前为止没有发生问题,但是我想问一下如果在上次更新时还有一些子工作线程,向量重新分配给更大的内存块时是否会出现问题。
或者在这种多线程的情况下使用向量是否安全?因为它不是线程安全的吗?

编辑: 由于只有当updater调用vector :: resize(N + M,0)时才会发生插入,是否有任何可能的解决方案来解决我的问题?由于STL向量的良好性能,我不愿意用可锁定的向量来替换它,或者在这种情况下是否有任何高性能,已知和无锁向量?

回答

19

我想问一问题是否在将向量重新分配给一个较大的内存块时是否会发生问题,如果有前面的更新留下一些子工作线程。

是的,这将是非常糟糕的。

如果您使用的是来自多个线程的容器,并且至少有一个线程可能执行某些可能会修改容器状态的操作,则必须对容器进行同步。

std::vector改变其大小(特别是,插入和删除)改变其状态,即使不需要重新分配的情况下,任何东西(任何插入或擦除要求的std::vector内部尺寸簿记数据进行更新) 。


一个解决方案,您的问题将有生产者动态分配std::vector并使用std::shared_ptr<std::vector<T> >拥有它,让这个std::shared_ptr给每个消费者。

当生产者需要添加更多数据时,它可以动态分配新的std::vector,其中包含一个新的,更大的尺寸以及旧std::vector中元素的副本。然后,当您分拆新消费者或使用新数据更新消费者时,只需将它们的std::shared_ptr分配给新的std::vector即可。

+0

@詹姆斯麦克奈利斯:是的。这是一个很好的建议。我可以自己做重新分配。实际上,矢量被包装在一个包含矢量指针的类中。它不是shared_ptr,但我可以轻松构建一个新的更大的矢量,从旧的元素中复制元素,将其删除。那么复制大内存块的最快方法是什么? CopyMemory的()? – 2010-12-03 15:53:26

+1

会不会更简单的解决方案是使用`std :: deque`而不是矢量?这完全避免了重新分配,同时仍然提供与矢量几乎相同的性能。 – jalf 2010-12-03 16:30:36

1

您的工作人员是如何决定处理数据线程安全的?工人和生产者之间是否存在任何信号?如果不是的话,生产者可能会导致矢量在工作时移动,这绝对是一个问题。尽管这可以通过移动到std::deque来修复,但可以修改它(注意std::deque使push_back上的迭代器无效,但对元素的引用不受影响)。