c++ - 从模块导入时,线程局部静态变量未初始化

标签 c++ visual-c++ c++20 c++-modules

我一直在尝试使用 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/

相关文章:

c++ - 无法调用 MFC ActiveX 中的方法

c++ - 如何制作全屏滚动消息框或窗口?

c++ - 用三向运算符嵌套生成比较运算符?

c++ - 如何使用 xcb 正确设置 utf8 窗口标题?

使用字符串函数进行 C++ 循环

C++虚函数和线程

c++ - 是否可以从 Visual Studio 调试器检测 GDI 泄漏?

模块中的 C++ "Using"

c++ - 跨进程加载 DLL - 如何进行某些操作 "singleton-like"

c++ - ifstream::open 在 Visual Studio Debug模式下不工作