【问题标题】:Memory semantics of initialization in multithread environment (C++)多线程环境中初始化的内存语义(C++)
【发布时间】:2017-07-20 02:09:16
【问题描述】:

我不确定 C++ 初始化过程的内存语义。 假设我们有以下程序。

#include <iostream>
#include <thread>

using namespace std;

void func(int* arr, int s)
{
    for (int i = 0; i < s; ++i)
    {
        cout << arr[i] << endl;
    }
}

int main(int argc, char *argv[])
{
    int *a = new int[10];
    for (int i = 0; i < 10; ++i)
    {
        a[i] = i;
    }

    // Do I need some sort of memory barrier here?
    std::thread t(func, a, 10);
    t.join();
    return 0;
}

新线程会看到正确初始化的数组吗?或者我是否需要在两者之间插入某种内存屏障。 C++语言如何定义初始化的内存语义?

我担心的是所有对数组 a[10] 的写入都可能位于一个 cpu 的写入缓冲区中,并且我们在不同的 cpu 上启动了一个新线程,它可能不会观察到初始化写入。

我们是否需要用于初始化的内存栅栏,以便稍后在不同 cpu 上运行的线程能够观察到?

【问题讨论】:

    标签: c++ multithreading concurrency memory-fences


    【解决方案1】:

    在执行线程构造函数之前父进程中的操作与子进程中运行的线程过程之间存在“先发生”关系。特别是标准说(f 是线程过程):

    同步:构造函数调用的完成与f副本的调用开始同步。

    这可以在[thread.thread.constr]部分找到

    【讨论】:

    • 感谢您的引用。我很难阅读标准。我找到了你的报价。通过“同步”,我想这意味着编译器可能会在调用 f 的副本之前插入栅栏,以确保观察到调用 f 之前的所有存储?
    • @OliverYoung:该标准没有提及内存栅栏,因为并非所有 CPU 架构都需要它们。该标准说明了编译器需要确保副作用可见的位置,以及操作重叠(创建竞争条件)的位置,并且编译器负责使用任何 CPU 功能提供指定的行为。
    • 我明白了。需要非常清楚的是,初始化部分同步/“之前发生”的 f 副本的调用。这意味着没有竞争条件,也不需要同步操作,对吧?
    • @OliverYoung:正确。虽然说“不需要额外的同步操作”会更正确,因为启动线程已经是一个同步操作,正如这个标准引用所记录的那样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 2013-06-27
    • 1970-01-01
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    相关资源
    最近更新 更多