为什么使用 thread_local 变量会导致段错误?

Why does using thread_local variable cause a segfault?

我在 class A 中创建了一个堆上数组,然后创建了一个 thread_local A 对象。通过 A 访问堆上存储会导致段错误,为什么?

#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
#include <vector>

class A {
 public:
  A() {
    std::cout << ">>>> constructor >>>>" << std::endl;
    a = new int[10];
  }
  ~A() {
    std::cout << ">>>> destructor >>>>" << std::endl;
    delete[] a;
  }
  void set(int x) { a[0] = x; }
  int get() const { return a[0]; }

 private:
  int* a;
};

int main() {
  std::thread t1;
  {
    thread_local A t;
    t1 = std::thread([]() {
      t.set(1);
      std::cout << t.get() << std::endl;
    });
  }

  t1.join();
  std::cout << ">>>> main >>>>" << std::endl;
}

结果:

>>>> constructor >>>>
Segmentation fault (core dumped)

t 仅在 when your code passes through it in main 中初始化。由于 t1 是一个单独的线程,它的 t 是变量的一个单独实例,但它没有被初始化,因为 t1 中的代码从不执行声明 t 的行。

如果我们将 t 更改为全局 then the rules are different 并且每个线程自动初始化它自己的 t 副本并且您的代码正确执行:

thread_local A t;

int main() {
  std::thread t1;
  {
    t1 = std::thread([]() {
      t.set(1);
      std::cout << t.get() << std::endl;
      });
  }

  t1.join();
  std::cout << ">>>> main >>>>" << std::endl;
}

与您的问题无关,但您应该确保您的代码遵守 rule of three 并删除或实现复制构造函数和赋值运算符,否则此代码将具有未定义的行为,因为两个对象都将尝试删除 a:

A a1;
A a2 = a1;