简体   繁体   English

C ++ STL向量迭代器与索引访问和线程安全性

[英]C++ STL vector iterator vs indexes access and thread safety

I am iterating over an STL vector and reading values from it. 我正在迭代STL向量并从中读取值。 There is another thread which can make changes to this vector. 还有另一个线程可以对此向量进行更改。 Now, if the other thread inserts or removes and element from the vector, it invalidates the iterator. 现在,如果另一个线程从向量中插入或移除元素,则它会使迭代器无效。 There is no use of locks involved. 没有使用锁。 Does my choice of accessing the container through indexes(Approach 1) in place of iterators(Approach 2) make it thread safe? 我选择通过索引(方法1)代替迭代器访问容器(方法2)是否使线程安全? What about performance? 性能怎么样?

struct A{int i; int j;};

Approach 1: 方法1:

   size_t s = v.size();//v contains pointers to objects of type A
    for(size_t i = 0; i < s; ++i)
    {
         A* ptr = v[i];
         ptr->i++;
    }

Approach 2: 方法2:

std::vector<A*>::iterator begin =  v.begin();
std::vector<A*>::iterator end =  v.end();
for(std::vector<A*>::iterator it = begin; it != end; ++it)
{
     A* ptr = *it;
     ptr->i++: 
}

The thread-safety guarantees for standard library containers are very straight forward (these rules were added in C++ 2011 but essentially all current library implementations conform to these requirements and impose the corresponding restrictions): 标准库容器的线程安全保证非常简单(这些规则在C ++ 2011中添加,但基本上所有当前库实现都符合这些要求并强加相应的限制):

  1. it is OK to have multiple concurrent readers 拥有多个并发读者是可以的
  2. if there is one thread modifying a container there shall be no other thread accessing (reading or writing) it 如果有一个线程修改容器,则不应有其他线程访问(读取或写入)它
  3. the requirements are per container object 要求是每个容器对象

Effectively, this means that you need to use some mechanism external to the container to guarantee that a container accessed from multiple threads is handled correctly. 实际上,这意味着您需要使用容器外部的某种机制来保证从多个线程访问的容器得到正确处理。 For example, you can use a mutex or a readerwriter lock. 例如,您可以使用互斥锁或读写器锁。 Of course, most of the time containers are accessed only from one thread and things work just fine without any locking. 当然,大多数时候只能从一个线程访问容器,而且没有任何锁定就可以正常工作。

Without using explict locks you will cause data races and the behavior is undefined, independent of whether you use indices or iterators. 如果不使用explict锁,您将导致数据争用并且行为未定义,与您是否使用索引或迭代器无关。

No. STL containers are not thread safe. 不.STL容器不是线程安全的。

You should provide exclusive access to each thread(the one that removes/the one that adds), while they're accessing the vector. 在访问向量时,您应该提供对每个线程(删除/添加的线程)的独占访问权限。 Even when using indexes, you might be removing the i-th elemenet, making the pointer you had retrieved, invalid. 即使使用索引,您可能会删除第i个elemenet,使您检索到的指针无效。

OP "Does my choice of accessing the container through indexes(Approach 1) in place of iterators(Approach 2) make it thread safe?" OP“我选择通过索引(方法1)代替迭代器访问容器(方法2)是否使线程安全?”

No, neither approach is thread safe once you start writing to your data structure. 不,一旦开始写入数据结构,这两种方法都不是线程安全的。

Therefore you will need to serialize access to your data structure. 因此,您需要序列化对数据结构的访问。

To save you a lot of time and frustration there a lot of ready-rolled solutions eg 为了节省您大量的时间和挫折,有许多现成的解决方案,例如

Intel Threading Building Blocks (TBB) which comes with thread safe containers such as concurrent_vector . 英特尔线程构建模块(TBB),它带有线程安全容器,例如concurrent_vector

http://threadingbuildingblocks.org/ http://threadingbuildingblocks.org/

A concurrent_vector is a container with the following features: concurrent_vector是具有以下功能的容器:

  • Random access by index. 按索引随机访问。 The index of the first element is zero. 第一个元素的索引为零。
  • Multiple threads can grow the container and append new elements concurrently. 多个线程可以增长容器并同时追加新元素。
  • Growing the container does not invalidate existing iterators or indices.* 增长容器不会使现有的迭代器或索引无效。*

OP "What about performance?" OP“性能怎么样?”

Not knowable. 不可知。 Different performance on different systems with different compilers but not known to be large enough to influence your choices. 不同编译器在不同系统上的不同性能,但不知道其大小足以影响您的选择。

Could your algorithm work with a fixed size array? 您的算法可以使用固定大小的数组吗?

Reason I ask is that the only way, logically, to have multiple threads modifying (most kinds of) container in a thread-safe, lock-free way is to make the container itself invariant. 我要问的原因是逻辑上,唯一的方法是让线程安全,无锁的方式修改(大多数种类)容器的多个线程是使容器本身不变。 That means the CONTAINER doesn't ever change within the threads, just the elements within it. 这意味着CONTAINER永远不会在线程内发生变化,只会在其中的元素内发生变化。 Think of the difference between messing with the insides of boxcars on a train, vs. actually adding & removing entire boxcars FROM that train as its moving down the tracks. 想想弄乱火车上的厢式车内部与实际添加和移除整个厢式车之间的区别,因为它沿着轨道向下移动。 Even meddling with the elements is only safe if your operations on that data observe certain constraints. 即使对这些元素进行操作,如果您对该数据的操作遵守某些约

Good news is that locks are not always the end of the world. 好消息是锁并不总是世界末日。 If multiple execution contexts (threads, programs, etc.) can hit the same object simultaneously, they're often the only solution anyway. 如果多个执行上下文(线程,程序等)可以同时命中同一个对象,那么它们通常是唯一的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM