使用索引迭代STL容器的安全方式,避免使用锁
Iterate over STL container using indices safe way to avoid using locks?
想知道以以下方式迭代STL容器(如vector)是否安全,以避免读/写锁定,但只允许任何"写"线程进行push_back()操作。
for (size_t i = 0; i < vec.size(); i++)
{
const T& t = *vec[i];
// do something with t
}
我知道迭代器可能会因容器的更改而失效,但如果我们确保初始容器大小足够大,可以容纳任何未来的添加,那么在不锁定读或写的情况下迭代元素也应该是安全的?
想知道以以下方式迭代STL容器(如vector)是否安全,以避免在读/写时锁定,但只允许任何"写"线程进行push_back()操作。
不要,这不是线程安全的。考虑一个试图读取值并进入当前缓冲区的线程。此时,第二个线程正在增长缓冲区,在第一个线程获得指向缓冲区的指针之后,但在它实际读取该值之前,第二个线程释放缓冲区的内容。第一个线程正在读取死对象,这是未定义的行为。
将问题限制在reserve()
-ed向量上(即避免增加缓冲区的问题),该方法仍然不是线程安全的。push_back()
中的代码将做类似的事情:
template <...>
class vector {
T *begin,*end,*capacity; // common implementation uses 3 pointers
void push_back(T value) {
if (end == capacity) { /* grow vector and insert */ }
else {
new (end) T(value);
++end;
}
}
};
这里的问题是,没有同步机制,编译器可以重新排序指令,增加end
并将其存储到内存中,然后调用T
的构造函数在缓冲区元素。如果发生了重新排序,那么reader线程可能会看到包含当前存储的值的size()
值,但该值尚未在vector中。
你不应该写代码依赖于它的实现细节,而不是矢量的导出API的一部分,据我所知。如果它是有文档记录的行为,你可以依赖它,如果不是,那就不要这样做。任何依赖于实现而非API文档部分的内容都可能在不同的平台上以及同一平台上工具的不同版本上发生变化。
同样,从@GManNickG的评论->你将有一个竞争条件在size()的调用,因为它将被修改和读取没有锁定在这里。
不能依赖关于迭代器不会失效的建议(因为还有很多空格)。你需要shared_mutex和shared_lock。(用法示例)
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 以线程安全的方式转换 C/C++ 中时区名称字符串的时区偏移量
- 如何以线程安全的方式更改目录?
- 使用字节数组具有单字节对齐方式的结构是否安全
- 在C++中以安全的方式将字符*转换为uint8_t*
- 如何以类型的安全方式分配UINT32_T :: MAX和UINT64_T的最小值
- 如何以异常安全的方式使用放置新?
- 如何以编程方式查找 Windows 上的活动安全提供程序
- 我可以在中断中写入向量,然后以安全的方式仅在主线程内读取吗?
- 使用boost :: asio :: strand以这种方式安全吗?
- 程序流并以安全而雄辩的方式正确返回Main()
- 以更健壮和类型安全的方式处理ASCII命令
- 访问"std::variant"的不安全、"noexcept"和无开销方式
- 以最新的C 的类型安全方式从枚举中随机选择元素
- 这种反转字符串的方式安全吗?
- C++以内存安全的方式使用给定向量的大小创建2D阵列
- Qt QTimer 以这种方式停止它是否安全
- C++:最安全的施放提升方式::<type>可选类型
- 使用模板对类层次结构进行函数重载的这种方式安全吗
- 这种使用std::string的方式安全吗?