我一直在尝试使用 C++20 模块,并在我尝试编写的第一个模块中发现了一个错误,其中函数中的线程局部静态局部变量未初始化(或更准确地说初始化为零),具体取决于随叫随到。
我已将问题归结为单个主模块接口(interface)单元中的一小段代码,没有实现文件,因此请原谅该代码没有任何实际意义,它只是为了演示问题。如果代码包含在 header 中,则该代码可以正常工作。
问题代码:Test.ixx
module;
#include <stdint.h>
#include <random>
export module Test;
export namespace Test {
__forceinline uint32_t TestFunc0() {
static thread_local uint32_t test_var = rand();
return test_var;
}
__forceinline uint32_t TestFunc1() {
static thread_local uint32_t test_var = rand();
return test_var;
}
__forceinline uint32_t TestFunc2() {
static thread_local uint32_t test_var = rand();
return test_var;
}
}
现在是main.cpp:
#include <iostream>
#include <ctime>
#include <random>
import Test;
int main()
{
srand(std::time(nullptr));
std::cout << Test::TestFunc0() << std::endl;
std::cout << Test::TestFunc1() << std::endl;
std::cout << Test::TestFunc2() << std::endl;
}
我期望的输出是:
(random number)
(random number)
(random number)
但我得到:
(random number)
0
0
如果我不使用 rand() (或任何其他函数)进行初始化,而是使用如下文字进行初始化:
__forceinline uint32_t TestFunc0() {
static thread_local uint32_t test_var = 10;
return test_var;
}
__forceinline uint32_t TestFunc1() {
static thread_local uint32_t test_var = 20;
return test_var;
}
__forceinline uint32_t TestFunc2() {
static thread_local uint32_t test_var = 30;
return test_var;
}
然后我得到:
0
0
0
请注意,__forceinline 可以替换为 inline,这没有什么区别,只要编译器决定内联该函数,无论是否指定,都会出现此问题。 如果在这些函数定义中使用 __forceinline 或 inline 关键字,那么在这种情况下编译器将决定不内联,问题代码将再次按预期工作。
此外,如果变量是静态的而不是 thread_local 静态的,也可以解决问题。
因此,如果使用函数调用进行初始化,则 main 调用的第一个函数中的 thread_local 静态变量将被初始化,对未首先调用的其他 TestFunc 的调用将保持未初始化/初始化为零。 如果使用文字初始化,则无论顺序如何,所有静态 thread_locals 都将被初始化为零。
就像我之前提到的那样,只有当这是一个模块而不是带有 header 时才会发生这种情况。我认为这也不是多个翻译单元的问题,因为 Test.asm 实际上是空的并且不包含实际的程序集。
我使用带有/Ox 的 MSVC 进行编译,但优化级别根本不会改变行为。我也没有尝试过任何其他编译器标志。
我认为我遗漏了一些非常明显的东西,因为这看起来太基本了,不可能是编译器错误。 有人知道为什么这没有像我预期的那样工作吗?我不习惯 C++ 中的 thread_local 存储,在这种情况下我是否需要做一些特殊的初始化?
最佳答案
Note that the __forceinline can be replaced with inline, it makes no difference, this problem occurs as long as the compiler decides to inline the function
那就是编译器错误。函数的内联不应对该函数的工作方式产生明显的影响。模块不会改变这一点。
关于c++ - 从模块导入时,线程局部静态变量未初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75768542/