向量引用运算符 [] 是线程安全的吗?
Posted
技术标签:
【中文标题】向量引用运算符 [] 是线程安全的吗?【英文标题】:Is the vector reference operator[] threadsafe for writing? 【发布时间】:2020-04-27 22:38:55 【问题描述】:假设我有以下代码 sn-p。
// Some function decleration
void generateOutput(const MyObj1& in, MyObj2& out);
void doTask(const std::vector<MyObj1>& input, std::vector<MyObj2>& output)
output.resize(input.size());
// Use OpenMP to run in parallel
#pragma omp parallel for
for (size_t i = 0; i < input.size(); ++i)
generateOutput(input[i], output[i]);
上述威胁安全吗?
我主要关心写信给output[i]
。
我需要某种锁定吗?还是没有必要?
例如:
// Some function prototype
void generateOutput(const MyObj1& in, MyObj2& out);
void doTask(const std::vector<MyObj1>& input, std::vector<MyObj2>& output)
output.resize(input.size());
// Use OpenMP to run in parallel
#pragma omp parallel for
for (size_t i = 0; i < input.size(); ++i)
MyObj2 tmpOutput;
generateOutput(input[i], tmpOutput);
#pragma omp critical
output[i] = std::move(tmpOutput);
我不担心阅读部分。正如this 回答中提到的,看起来阅读input[i]
是线程安全的。
【问题讨论】:
【参考方案1】:output[i]
不写信给output
。这只是对std::vector<MyObj2>::operator[]
的调用。它返回一个未命名的MyObj2&
,然后用于调用generateOutput
。后者是写入发生的地方。
我假设generateOutput
本身是线程安全的,MyObj2
也是,因为我们没有代码。所以在generateOutput
中写入MyObj2&
也是线程安全的。
因此,所有部分都是线程安全的。
【讨论】:
【参考方案2】:只要保证线程对完全独立的项目进行操作(即,没有某种同步,不同的不同线程不会访问任何项目)这是安全的。
由于您使用的是简单的并行 for 循环,其中每个项目仅被访问一次,因此这是安全的。
【讨论】:
【参考方案3】:要不对 std::vector 的实现做任何假设,您可以如下修改代码以使其成为线程安全的(指针地址将根据定义指向内存中的不同区域,因此是线程安全的)
// Some function decleration
void generateOutput(const MyObj1& in, MyObj2 *out); // use raw data pointer for output
void doTask(const std::vector<MyObj1>& input, std::vector<MyObj2>& output)
output.resize(input.size());
// Use OpenMP to run in parallel
auto data = output.data() ;// pointer on vector underlying data outside of OMP threading
#pragma omp parallel for
for (size_t i = 0; i < input.size(); ++i)
generateOutput(input[i], &data[i]); // access to distinct data elements ie addresses (indexed by i only in from each omp thred)
【讨论】:
在这种情况下,指针与引用有何不同?您不需要对std::vector
的实现做出假设。对容器中不同元素的安全访问源于标准(26.2.2.2,C++17)
你好。指针直接引用内存中的地址,因此如果指针不同,您就知道并发访问内存中的相同内容没有风险。由于向量方法的唯一使用是在多线程循环之外完成的,因此您知道无论 std::vector[i] 以何种方式实现都是安全的。但是我同意标准说它是安全的,所以引用或指针使用是等效的,前提是编译器/标准实现没有错误
1) 仅仅因为指针值不同,不是否暗示线程安全访问(别名,OpenMP 内存模型)。 2) 指针和引用没有区别,对这种特殊情况有任何影响(参见***.com/a/57492/620382)
在提供的示例中不能使用指针别名。我只是在回答这个例子。我不是在谈论引用与指针,而是在谈论 openmp 线程中向量方法的使用与否。如果没有从循环中调用 std::vector 方法,则对 std::vector 数据的访问是在所提供示例的上下文中是安全的。
好的,我明白了,感谢您的澄清。附言您需要交换 #pragma omp parallel for
和 data = ..
并添加 ;
以使代码正确。以上是关于向量引用运算符 [] 是线程安全的吗?的主要内容,如果未能解决你的问题,请参考以下文章