从父线程继承全局值

Inherit global value from parent thread

本文关键字:全局 继承 线程      更新时间:2023-10-16

子线程有没有办法从其父线程继承全局值?我知道静态线程局部变量的动态初始化:https://stackoverflow.com/a/23558302/3214670,但这不是真正的继承 - 在这个例子中,从线程内部创建的线程不会获得它们的父值,而是在 main 中设置的值。

所以我有如下所示的代码。谁能说出如何使子线程具有与其父线程相同的全局价值?

线程是这样创建的:

                        main thread
                        |         |
                       t1         t2
                        |         |
                      t11         t22

法典:

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <memory>
static int g = 1;
static thread_local int s = g;
std::mutex m;
void print(int i)
{
  std::unique_lock<std::mutex> u(m);
  std::cout << "thread " << i << " s = " << s << std::endl;
}
void bar(int i)
{
  print(i);
}
void foo(int i)
{
  print(i);
  std::this_thread::sleep_for(std::chrono::seconds(2));
  std::thread c(bar, 11*i);
  c.join();
}
int main()
{
  std::thread a(foo, 1);
  std::this_thread::sleep_for(std::chrono::seconds(1));
  g = 2;
  std::thread b(foo, 2);
  a.join();
  b.join();
  return 0;
}

输出:

thread 1 s = 1
thread 2 s = 2
thread 11 s = 2
thread 22 s = 2

我想要的输出是:

thread 1 s = 1
thread 2 s = 2
thread 11 s = 1
thread 22 s = 2

请注意,我不想将任何变量传递给线程,而是使用全局变量。

您所要求的是不可能的,原因很简单:线程之间没有父子关系。

有多种解决方法,例如自己构建这样的继承树,但这意味着您还必须维护此树。这意味着,无论何时启动线程,都必须在树中为新线程创建一个新条目,并且每当线程完成时,都必须删除相应的条目。这带来了一堆问题,因为首先你必须以线程安全的方式这样做(避免竞争条件)。其次,每次启动或停止线程时都必须这样做,这实际上意味着您必须调整线程启动的每个位置。其中一些地方甚至可能超出您的控制范围。或者,您可以尝试找到特定于操作系统的钩子来跟踪线程的创建和销毁,但C++本身并不能为您提供一个钩子。

总之,我建议你重新考虑你的设计。使用伪全局变量不仅是维护的噩梦,而且您的方法也难以实现。

没有

办法添加新的thread_local初始化样式,也没有内置的继承感或fork感。

如果你自己编码,这是可能的。只是要注意同步。在子线程完成读取源值之前,父线程无法更改其源值。(这已经给thread_local变量带来了问题:它们在访问时被延迟初始化,而不是在线程初始化时一次全部初始化。

早于thread_local的一个习惯用法是将线程句柄与线程本地状态一起封装在类中。父线程对象可以在将克隆作为子线程启动之前,使用其复制构造函数简单地克隆自身。然后,在子项启动之前,所有状态都已准备就绪,因此无需同步。

在该习惯用法中,指向线程类的指针将传递给新的线程函数。目前尚不清楚为什么foo不能接受指针参数;这是非常不寻常的。

在C++中,您有所有线程共享的普通全局变量,以及每个线程的本地thread_local变量。

您的请求在某种程度上是两者之间的混合:如果我理解正确,您希望在第一级使用每线程全局变量,但在第二级共享该变量。这简直是矛盾的,您当然可以编写符合您要求的代码,但不要使用您要求的工具。为了使这一点更加明显:就像要求一个全局变量,该变量仅对循环的奇数迭代是全局的。

但是,有不同的解决方案可以为您提供所需的结果。下面我为此目的对您的代码进行了一些更改:

不好的代码示例,使用全局提供所需的结果:

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <memory>
#include <atomic>
static std::atomic<int> g;
static thread_local int s = g;
std::mutex m;
void print(int i)
{
  std::unique_lock<std::mutex> u(m);
  std::cout << "thread " << i << " s = " << s << std::endl;
}
void bar(int i)
{
  print(i);
}
void foo(int i)
{
  print(i);
  int myVal;
  myVal= g;
  std::this_thread::sleep_for(std::chrono::seconds(2));
  g=myVal; // Not really good code anyway.
  std::thread c(bar, 11*i);
  c.join();
}
int main()
{
  g=1;
  std::thread a(foo, 1);
  std::this_thread::sleep_for(std::chrono::seconds(1));
  g = 2;
  std::thread b(foo, 2);
  a.join();
  b.join();
  return 0;
}

考虑到此解决方案是一个示例,肯定有改进要做。

我会向您推荐其他人已经做过的相同:将s值作为参数传递给thread 11thread 22