多个线程可以在不同的地方访问一个向量吗?
Posted
技术标签:
【中文标题】多个线程可以在不同的地方访问一个向量吗?【英文标题】:Can multiple threads access a vector at different places? 【发布时间】:2010-06-01 16:06:29 【问题描述】:假设我有一个 int 向量,我预先填充了 100 个值为 0 的元素。
然后我创建 2 个线程并告诉第一个线程用数字填充元素 0 到 49,然后告诉线程 2 用数字填充元素 50 到 99。这可以做到吗?否则,实现这一目标的最佳方法是什么?
谢谢
【问题讨论】:
在最近的 video 中,Stephan T. Lavavej 确认这很好用 @ 39:12 :) 好吧,我实现了它,它在我的 quad 上是 4 倍,在我的 duo 上是 2 倍,所以并不慢 【参考方案1】:是的,这应该没问题。只要你能保证不同的线程不会修改同一个内存位置,就没有问题。
【讨论】:
我认为这实际上应该是“......只要你保证没有线程修改另一个线程访问的内存位置,无论是读取还是写入访问。” 需要注意的是,即使它应该可以工作,但由于相互缓存失效,它很可能会很慢。 多个线程试图读取向量的相同内存位置怎么办?希望没问题?【参考方案2】:是的,对于大多数向量的实现,应该可以这样做。也就是说,这在大多数系统上的性能会很差,除非您有大量元素并且您正在访问彼此相距很远的元素,因此它们不会位于同一缓存行上......否则,在许多系统上,两个线程将来回使彼此的缓存无效(如果您经常读取/写入这些元素),从而导致两个线程中的大量缓存未命中。
【讨论】:
我相信 Windows/Linux 线程的实现不会使缓存失效,因为不同的线程在同一个虚拟内存上工作,不像不同的进程。 @Oak,这与操作系统无关。这是由处理器缓存实现的。在具有一致性缓存的 x86 等系统上,写入已被多个内核缓存的内存地址将需要发出读取独占(无效)操作以保持缓存一致性。【参考方案3】:“vector
不是线程安全的”这一事实并不意味着什么。
这样做没有问题。
此外,您不必在堆上分配向量(作为建议的答案之一)。您只需确保向量的 lifetime 涵盖线程的生命周期(更准确地说 - 这些线程访问向量的位置)。
当然,因为您希望两个线程都在 same 向量上工作 - 它们必须通过指针/引用而不是值从某处接收它。
从不同线程中访问数组的相同元素也绝对没有问题。但是,您应该知道您的线程不是唯一访问它的线程,并分别对待它。
简单来说——从不同的线程中访问一个数组是没有问题的。 从不同的线程访问相同的元素就像从不同的线程访问单个变量 - 相同的预防措施/后果。
您唯一需要担心的情况是添加新元素时,这在您的情况下是不可能的。
【讨论】:
【参考方案4】:C++11 起:
同一容器中的不同元素可以同时修改 由不同的线程,除了 std::vector 的元素 (例如,std::future 对象的向量可以接收值 来自多个线程)。
cppreference 详细讨论了容器here 的线程安全性。 在Quora post 中找到了链接。
【讨论】:
【参考方案5】:没有理由不能这样做。但是,一旦您开始混合访问(两个线程访问同一个元素),就会变得更具挑战性。
【讨论】:
【参考方案6】:vector
不是线程安全的。您需要保护线程之间的向量。在您的情况下,它取决于 vector
实现。如果vector内部数据是从不同线程访问\修改的,则完全依赖vector impl。
【讨论】:
假设他使用的是“向量”而不是向量 (c++/c) - 访问不同位置有什么危险?【参考方案7】:使用数组可以确定(线程不会访问相同的内存区域);但如前所述,如果您使用 std::vector 类,结果可能取决于它的实现方式。实际上,我看不到向量类上 [] 的实现如何是线程不安全的(假设线程尝试访问不同的“索引”),但它可能是。 解决方法是:坚持使用数组,或者使用信号量或类似的方式控制对向量的访问。
【讨论】:
【参考方案8】:这应该没问题,但由于错误共享,您最终会导致性能不佳,每个线程都可能使彼此的缓存行无效
【讨论】:
【参考方案9】:你所描述的很有可能,应该说得很好。
但是请注意,线程需要在std::vector*
上工作,即指向原始向量的指针——您可能应该在堆上分配向量,而不是在堆栈上。如果直接传递向量,则会调用复制构造函数并在每个线程上创建数据的单独副本。
还有很多更微妙的方法可以解决这个问题,就像多线程编程一样。但是原则上你描述的会很好用。
【讨论】:
为什么在 std::vector 提供迭代器时使用指向向量的指针。只要您不调整向量的大小,它们就会是有效的迭代器。以上是关于多个线程可以在不同的地方访问一个向量吗?的主要内容,如果未能解决你的问题,请参考以下文章