Is writing std::deque at different memory locations concurrently thread-safe?

浪尽此生 提交于 2021-01-26 19:33:47

问题


I have a std::deque<std::pair<CustomObj, int>> that doesn't change in size when starting the concurrent block.

The concurrent block reads each CustomObj of the deque and sets the int.

I can guarantee that the deque won't change size therefore it won't reallocate, and that each thread will only access a memory chunk of the deque but not the other thread's.

Does it lead to undefined behaviour reading and writing concurrently? Should I put the writing and reading in a mutual exclusion zone?


回答1:


Surprisingly to me, there is actually a very clear section about this in the current standard itself:

(C++17, 26.2.2 Container data races, 2)

  1. Notwithstanding 20.5.5.9, Implementations are required to avoid data races when the contents of the contained object in different elements in the same container, excepting vector<bool>, are modified concurrently.

Also you are allowed to call the following accessors without worry:

  1. For purposes of avoiding data races (20.5.5.9), implementations shall consider the following functions to be const: begin, end, rbegin, rend, front, back, data, find, lower_bound, upper_bound, equal_range, at and, except in associative or unordered associative containers, operator[].

Since std::deque is neither exception, you are fine to concurrently call any of those functions to get different elements and modify them. Just make sure to properly isolate any modifications to the container itself from the parallel region where you concurrently access and modify the elements.

For example this would be wrong:

std::dequeue<...> dq;
#pragma omp master
{
    ...
    dq.emplace(...);
}
// no implicit barrier here,
// use omp barrier or change to omp single instead of master
#pragma omp for
for (... i; ...)
    dq[i].second = compute(dq[i]);



回答2:


As long as you can guarantee that the the size of the deque doesn't change and only one thread will ever write to a particular element then yes, that is safe. You only have an issue when you try to modify the deque (change it's size) or when you have multiple threads reading and writing to a single element inside the deque.

One thing you could experience though is called false sharing. That is the process of a single cache line having elements that are being used by multiple threads. Since a thread write would dirty the cache line the whole thing needs to be re-synchronized which will hurt performance




回答3:


Arule for all standard containers is:

  • Many readers or one writer on the entire container and on each element.
  • Individual element reading or modification (not adding/removing an element) is also read operation on the container.

That is only modestly too strong. You can do a small number of things that violate the above rules without being a race condition under the standard.


In the standard, this is usually worded in terms of const methods on the container. A read method is const, a write method is not const. The exception is that begin() and end() and data() (methods that just return iterators) that are non-const count as const.

For iteration and element access, it is worded in terms of iterator invalidation. Many operations invalidate iterators, and if an iterator is invalidated in an unsequenced manner with its use it is a race condition.

As an example of a case where the rule of thumb above says "no" but the standard says "ok":

You can have a map and a reference to a value in the map stored. You can be editing the value while another thread adds key value pairs to the map.

As no iterators are invalidated by the map, and you aren't touching the key, I beleive there is no race condition.



来源:https://stackoverflow.com/questions/50626405/is-writing-stddeque-at-different-memory-locations-concurrently-thread-safe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!