STL 向量和线程安全

2021-12-21 00:00:00 multithreading thread-safety vector c++ stl

假设我有一个包含 N 个元素的向量,但是这个向量中最多有 n 个元素具有有意义的数据.一个更新线程更新第 n 个或第 n+1 个元素(然后设置 n = n+1),还会检查 n 是否太接近 N 并在必要时调用 vector::resize(N+M).更新后,线程调用多个子线程读取最多第n个数据并做一些计算.

Let's say I have a vector of N elements, but up to n elements of this vector have meaningful data. One updater thread updates the nth or n+1st element (then sets n = n+1), also checks if n is too close to N and calls vector::resize(N+M) if necessary. After updating, the thread calls multiple child threads to read up to nth data and do some calculations.

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

It is guaranteed that child threads never change or delete data, (in fact no data is deleted what so ever) and updater calls children just after it finishes updating.

目前没有出现任何问题,但是我想问一下,在重新分配vector到更大内存块的过程中,如果上次更新留下了一些子工作线程,是否会出现问题.
或者在这种多线程的情况下使用vector是否安全,因为它不是线程安全的?

So far no problem has occured, but I want to ask whether a problem may occur during reallocating of vector to a larger memory block, if there are some child working threads left from the previous update.
Or is it safe to use vector, as it is not thread-safe, in such a multithreaded case?

由于只有在更新程序调用 vector::resize(N+M,0) 时才会进行插入,所以我的问题有什么可能的解决方案吗?由于 STL 向量的出色性能,我不愿意用可锁定向量替换它,或者在这种情况下是否有任何高性能、已知和无锁向量?

Since only insertion takes place when the updater calls vector::resize(N+M,0), are there any possible solutions to my problem? Due to the great performance of STL vector I am not willing to replace it with a lockable vector or in this case are there any performant,known and lock-free vectors?

推荐答案

请问在将vector重新分配到更大的内存块时是否会出现问题,如果上次更新留下了一些子工作线程.

I want to ask whether a problem may occur during reallocating of vector to a larger memory block, if there are some child working threads left from the previous update.

是的,这会很糟糕.

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

If you are using a container from multiple threads and at least one thread may perform some action that may modify the state of the container, access to the container must be synchronized.

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

In the case of std::vector, anything that changes its size (notably, insertions and erasures) change its state, even if a reallocation is not required (any insertion or erasure requires std::vector's internal size bookkeeping data to be updated).

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

One solution to your problem would be to have the producer dynamically allocate the std::vector and use a std::shared_ptr<std::vector<T> > to own it and give this std::shared_ptr to each of the consumers.

当生产者需要添加更多数据时,它可以动态分配一个新的std::vector,它具有新的、更大的尺寸和旧std::vector 元素的副本.然后,当您剥离新消费者或使用新数据更新消费者时,您只需将 std::shared_ptr 赋予新的 std::vector.

When the producer needs to add more data, it can dynamically allocate a new std::vector with a new, larger size and copies of the elements from the old std::vector. Then, when you spin off new consumers or update consumers with the new data, you simply need to give them a std::shared_ptr to the new std::vector.

相关文章