从父线程继承全局值

时间:2016-01-15 07:42:41

标签: c++ multithreading

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

所以我有一个如下代码。任何人都可以告诉如何让子线程与父母具有相同的全球价值吗?

线程是这样创建的:

                        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

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

3 个答案:

答案 0 :(得分:2)

由于一个简单的原因,你所要求的是不可能的:线程之间没有父子关系。

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

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

答案 1 :(得分:1)

无法添加thread_local初始化的新样式,并且没有内置的继承感或fork

如果您自己编码,这是可能的。请注意同步。在子线程完成读取之前,父线程无法更改其源值。 (这已经给thread_local变量带来了问题:它们在访问时被懒惰地初始化,而不是在线程初始化时立即初始化。)

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

在那个习语中,指向线程类的指针将被传递给新的线程函数。目前尚不清楚为什么foo不能采用指针参数;这很不寻常。

答案 2 :(得分:1)

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

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

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

不是很好的代码示例,使用global来提供所需的结果:

#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