【问题标题】:C++ local variables and threads (not thread_local)C++ 局部变量和线程(不是 thread_local)
【发布时间】:2013-02-19 12:00:24
【问题描述】:

本地数组和线程交互的 C++98 和 C++11 内存模型是什么?

不是指的是 C++11 thread_local 关键字,它与全局变量和静态变量有关。

相反,我想了解在编译时分配的数组的线程保证行为是什么。编译时我的意思是“int array[100]”,这与使用 new[] 关键字的分配不同。我不是指静态变量。

例如,假设我有以下结构/类:

struct xyz { int array[100]; };

还有以下功能:

void fn(int x) {
  xyz dog;
  for(int i=0; i<100; ++i)  { dog.array[i] = x; }
  // do something else with dog.array, eg. call another function with dog as parameter
  }

从多个线程调用 fn() 是否安全? 看来C++内存模型是:所有局部非静态变量和数组都分配在栈上,每个线程都有自己的栈。这是真的吗(即这是标准的正式一部分)?

【问题讨论】:

    标签: c++ multithreading parallel-processing thread-safety local-variables


    【解决方案1】:

    C++98 没有提到线程。用 C++98 编写但使用线程的程序没有 C++98 定义的含义。当然,线程扩展为线程提供稳定的私有局部变量是明智的,而且它们通常会这样做。但是可能存在不是这种情况的线程:例如,在某些 Unix 系统上由vfork 创建的进程,父子进程将在同一个堆栈帧中执行,因为vfork 中的v 意味着不克隆地址空间,vfork 也不会将新进程重定向到不同的函数。

    在 C++11 中,有线程支持。单独 C++11 线程中单独激活链中的局部变量不会干扰。但是,如果您跳出语言并抽出vfork 或任何类似的东西,那么所有的赌注都会像以前一样。

    但这里有一些东西。 C++ 现在有闭包。如果两个线程都调用同一个闭包怎么办?然后你有两个线程共享相同的局部变量。闭包就像一个对象,它捕获的局部变量就像成员。如果两个或多个线程调用同一个闭包,那么你就有一个事实上的多线程对象,其成员(即捕获的词法变量)是共享的。

    一个线程也可以简单地将其局部变量的地址传递给另一个线程,从而使它们成为共享的。

    【讨论】:

    • 我会区分按引用捕获和按值捕获,因为按值捕获不会在线程之间共享任何内容。
    • vfork() 阻塞父进程,直到子进程终止或加载另一个可执行映像,如果子进程调用任何其他函数或从当前函数返回,它将破坏父堆栈并导致在未定义的行为中。我看不出如何使用vfork() 实现有用的线程。
    • @HristoIliev 在您正在查看的某些系统上可能是这样,但在 Unix 中则不然。我在这里没有看到任何关于阻止父母的信息:pubs.opengroup.org/onlinepubs/007908775/xsh/vfork.html
    • @Zeta 按值捕获根本不是捕获。 (好吧,只有在一切都是不可变的语言中。)如果我们可以修改捕获的变量,使得原始变量保持不变,那么它就不是捕获的变量。你可以把它叫做一个,甚至把它写成一个标准,就像你可以把一条狗的尾巴叫做另一条腿一样。
    • 这是我没有得到的一件事:如果闭包通过引用获得 local 变量,然后在单独的线程中启动 → 所以在父线程中函数返回,并且变量不再有效——变量对于在线程中启动的闭包仍然有效吗?我问是因为例如在 Common LISP 中它仍然有效。但正如我所知,在 C++ 中,局部变量通常分配在堆栈中,所以我不确定这里的情况如何。
    【解决方案2】:

    这样的变量是在栈上分配的,因为每个线程都有自己的栈,所以使用局部数组是完全安全的。它们与例如没有什么不同。本地ints.

    【讨论】:

    • 谢谢。这是用 C++11 标准明确编写的吗?
    • @mtall:间接的。函数体中的所有非静态变量都是函数范围的一部分,并且具有自动存储期限。这也适用于std::thread::thread(F&amp;&amp;,Args&amp;&amp;...) 调用的函数。因此,如果您想将所有内容拼凑在一起,则必须阅读四个不同的部分。
    • 最后,每次调用fn 都会创建自己的xyz 实例。所以如果两个线程同时调用fn,那么两个线程都会创建并修改自己的xyz实例,这是线程安全的。
    猜你喜欢
    • 2020-01-23
    • 2021-12-15
    • 2020-02-04
    • 1970-01-01
    • 2023-02-14
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    相关资源
    最近更新 更多