向量引用运算符 [] 是线程安全的吗?

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&lt;MyObj2&gt;::operator[] 的调用。它返回一个未命名的MyObj2&amp;,然后用于调用generateOutput。后者是写入发生的地方。

我假设generateOutput 本身是线程安全的,MyObj2 也是,因为我们没有代码。所以在generateOutput 中写入MyObj2&amp; 也是线程安全的。

因此,所有部分都是线程安全的。

【讨论】:

【参考方案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 fordata = .. 并添加 ; 以使代码正确。

以上是关于向量引用运算符 [] 是线程安全的吗?的主要内容,如果未能解决你的问题,请参考以下文章

对 std::vector 元素的赋值是线程安全的吗?

<vector> 在不同位置读/写是线程安全的吗?

java是线程安全的吗

HashMap是线程安全的吗?如何实现线程安全?

C++ 线程安全括号运算符代理

lua引擎本身是线程安全的吗