C ++ 11 thread_local变量可以从父线程继承其初始值吗? [英] Can a C++11 thread_local variable inherit its initial value from the parent thread?

查看:241
本文介绍了C ++ 11 thread_local变量可以从父线程继承其初始值吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'd like to have a thread_local variable to change the level of logging applied in each thread of my application. Something like so:

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

默认值应为 trace_level :: log 对于主线程,当应用程序启动时,但如果它在启动其他线程之前更改,那么我想让子线程以父的当前值开始。

The default value should be trace_level::log for the main thread when the application starts, but if it is changed before launching other threads, then I would like the child threads to start with the current value of the parent.

有没有办法这样做使用 thread_local 变量?因为这个代码被隐藏在库中,所以不是在每个线程开始时手动设置值的选项。

Is there any way to do this using a thread_local variable? Since this code is buried in a library it is not an option to simply set the value manually at the start of each thread.

推荐答案

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

This already happens if the initialization is dynamic. The standard requires that variables with "thread storage duration" and dynamic initialization be initialized sometime between the start of the thread and the 'first odr-use'. However, since you generally can't control exactly when that initialization will occur (other than sometime after the thread object is created and sometime before the thread ends - assuming the thread local variable actually gets used by the thread) the problem is that the thread local variable might get initialized with a value that your main thread sets after the thread is created.

对于一个具体的例子, p>

For a concrete example, consider:

#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()调用注释掉如上,我得到以下输出(通常):

With the sleep_for() call commented out as above, I get the following output (usually):

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



sleep_for()取消注释,我得到(通常):

However, with the sleep_for() uncommented, I get (again - usually):

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

因此,只要你愿意在一个线程将获得的日志级别有点不确定性,如果级别在主线程中改变后不久线程启动,你可能只是做自己想要做的很自然。

So as long as you're willing to live with a bit of uncertainty regarding which logging level a thread will get if the level gets changed in the main thread soon after the thread starts, you can probably just do what you're looking to do pretty naturally.

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

There's one remaining caveat - data races. The code above has a data race on the log_level variable, so it actually has undefined behavior. The fix for that is to make the variable either an atomic type or wrap it in a class that uses a mutex to protect updates and reads from data races. So change the declaration of the global log_level to:

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






标准引文:


Standards citations:


3.6.2非本地变量的初始化[basic.start.init]

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

... Non - 具有线程存储持续时间的本地变量由于线程执行而初始化为
。 ...

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


3.7 .2 / 2线程存储持续时间[basic.stc.thread]

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

具有线程存储持续时间的变量应在
之前初始化它的第一次使用(3.2 ),并且如果被构造,应该在
线程退出。

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 ++ 11 thread_local变量可以从父线程继承其初始值吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆