gpt4 book ai didi

c++ - C++11 thread_local 变量可以从父线程继承它的初始值吗?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:43:28 24 4
gpt4 key购买 nike

我想要一个 thread_local 变量来更改应用于我的应用程序的每个线程的日志记录级别。像这样:

enum class trace_level { none, error, warning, log, debug, verbose };
static thread_local trace_level min_level = trace_level::log;

应用程序启动时主线程的默认值应该是trace_level::log,但是如果在启动其他线程之前改变它,那么我希望子线程从当前开始 parent 的值(value)。

有没有办法使用 thread_local 变量来做到这一点?由于此代码隐藏在库中,因此无法在每个线程开始时手动简单地设置值。

最佳答案

如果初始化是动态的,这已经发生了。该标准要求具有“线程存储持续时间”和动态初始化的变量在线程开始和“第一次 odr-use”之间的某个时间进行初始化。但是,由于您通常无法准确控制初始化何时发生(除了创建线程对象之后的某个时间和线程结束之前的某个时间 - 假设线程局部变量实际上被线程使用)问题是线程局部变量可能会使用您的主线程在线程创建后 设置的值进行初始化。

举个具体的例子,考虑一下:

#include <stdio.h>

#include <chrono>
#include <functional>
#include <thread>
#include <string>

using std::string;

enum class trace_level { none, error, warning, log, debug, verbose };

trace_level log_level = trace_level::log;


static thread_local trace_level min_level = log_level;
void f(string const& s)
{

printf("%s, min_level == %d\n", s.c_str(), (int) min_level);
}



int main()
{
std::thread t1{std::bind(f,"thread 1")};

//TODO: std::this_thread::sleep_for(std::chrono::milliseconds(50));

log_level = trace_level::verbose;
std::thread t2{std::bind(f,"thread 2")};

t1.join();
t2.join();
}

如上注释掉 sleep_for() 调用后,我得到以下输出(通常):

C:\so-test>test
thread 1, min_level == 5
thread 2, min_level == 5

然而,在 sleep_for() 取消注释的情况下,我得到(再次 - 通常):

C:\so-test>test
thread 1, min_level == 3
thread 2, min_level == 5

因此,如果主线程中的日志级别在线程启动后不久发生更改,那么只要您愿意忍受关于线程将获得哪个日志级别的不确定性,您就可以按照自己的意愿去做看起来很自然。

还有一个警告 - 数据竞争。上面的代码在 log_level 变量上存在数据竞争,因此它实际上具有未定义的行为。解决方法是使变量成为原子类型或将其包装在使用互斥锁的类中以保护更新和读取数据竞争。因此,将全局 log_level 的声明更改为:

std::atomic<trace_level> log_level(trace_level::log);

标准引用:

3.6.2 Initialization of non-local variables [basic.start.init]

... Non-local variables with thread storage duration are initialized as a consequence of thread execution. ...

3.7.2/2 Thread storage duration [basic.stc.thread]

A variable with thread storage duration shall be initialized before its first odr-use (3.2) and, if constructed, shall be destroyed on thread exit.

关于c++ - C++11 thread_local 变量可以从父线程继承它的初始值吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23555612/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com