我的编译器是否忽略了我未使用的静态thread_local类成员
Did my compiler ignore my unused static thread_local class member?
我想在我的类中进行一些线程注册,所以我决定添加对thread_local
功能的检查:
#include <iostream>
#include <thread>
class Foo {
public:
Foo() {
std::cout << "Foo()" << std::endl;
}
~Foo() {
std::cout << "~Foo()" << std::endl;
}
};
class Bar {
public:
Bar() {
std::cout << "Bar()" << std::endl;
//foo;
}
~Bar() {
std::cout << "~Bar()" << std::endl;
}
private:
static thread_local Foo foo;
};
thread_local Foo Bar::foo;
void worker() {
{
std::cout << "enter block" << std::endl;
Bar bar1;
Bar bar2;
std::cout << "exit block" << std::endl;
}
}
int main() {
std::thread t1(worker);
std::thread t2(worker);
t1.join();
t2.join();
std::cout << "thread died" << std::endl;
}
代码很简单。我的Bar
类有一个静态thread_local
成员foo
。如果创建了静态thread_local
Foo foo
,则表示创建了线程。
但是,当我运行代码时,Foo()
中没有打印任何内容,如果我删除Bar
的构造函数(使用foo
(中的注释,代码就可以正常工作。
我在GCC(7.4.0(和Clang(6.0.0(上尝试过,结果是一样的。我猜编译器发现foo
是未使用的,并且不会生成实例。所以
- 编译器是否忽略了
static thread_local
成员?我该怎么办为此进行调试 - 如果是,为什么一个普通的
static
成员没有这个问题
您的观察没有问题。[basic.stc.static]/2禁止消除具有静态存储持续时间的变量:
如果具有静态存储持续时间的变量具有初始化或具有副作用的析构函数,即使它似乎未使用,除了类对象或其复制/移动可能按照[class.copy]的规定删除。
此限制不适用于其他存储持续时间。事实上,〔basic.stc.thread〕/2说:
具有线程存储持续时间的变量应在其第一次odr使用,如果构造,则应在线程退出。
这表明,除非使用odr,否则不需要构造具有线程存储持续时间的变量。
但为什么会出现这种差异?
对于静态存储持续时间,每个程序只有一个变量实例。其构造的副作用可能是显著的(有点像程序范围的构造函数(,因此需要副作用。
然而,对于线程本地存储持续时间,存在一个问题:一个算法可能会启动很多线程。对于这些线程中的大多数,变量是完全不相关的。如果一个调用std::reduce(std::execution::par_unseq, first, last)
的外部物理模拟库最终创建了大量foo
实例,那将是非常有趣的,对吧?
当然,构建未使用odr的线程本地存储持续时间变量(例如,线程跟踪器(的副作用可能是合法的。然而,保证这一点的优势不足以弥补上述缺点,因此只要不使用这些变量,就可以消除这些变量。(不过,你的编译器可以选择不这样做。你也可以在std::thread
周围制作自己的包装器来处理这个问题。(
我在"线程本地存储的ELF处理"中找到了这些信息,它可以证明@L.F.的答案
此外,运行时支持应避免创建线程本地存储(如果不需要(。例如,已加载模块可能只由组成过程分配所有线程的存储。需要一种懒惰的方法。这不多由于需要处理动态加载的对象已经需要识别尚未识别的存储已分配。这是停止所有线程和为所有线程分配存储空间,然后再让它们再次运行。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- #为""定义宏;静态";针对不同的上下文
- cmake如何在fedora工作站中找到boost静态库包
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 将公共但非静态的成员函数与ALGLIB集成
- cmake在我的项目中所需的所有静态库都不成功
- C++从另一个类访问公共静态向量的正确方法是什么
- 基于boost的程序的静态链接——zlib问题
- 在静态库中嵌入类方法
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 如何在C++中获得"静态纯虚拟"功能?
- 私有类型的静态常量成员
- 使用gcc从静态链接的文件中查找可选符号
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 如何在C++中使用非静态成员函数作为回调函数
- 将静态库链接到不带-fPIC的共享库中
- 分离一个静态常量 std::thread?
- 尝试使用 std::vector<std::thread时出现静态断言失败错误>
- std::thread::hardware_concurrency和静态初始化
- 链接器在编译使用Boost的可执行文件时出错.使用Boost.Thread链接到静态库的线程