c++ 线程周期关键字thread_local

thread_local变量是C++ 11新引入的一种存储类型。它会影响变量的存储周期(Storage duration),C++中有4种存储周期:
1.automatic (自动分配, 栈变量)
2.static
3.dynamic (动态分配,malloc)
4.thread
有且只有thread_local关键字修饰的变量具有线程周期(thread duration),这些变量(或者说对象)在线程开始的时候被生成(allocated),在线程结束的时候被销毁(deallocated)。并且每 一个线程都拥有一个独立的变量实例(Each thread has its own instance of the object)。thread_local 可以和static 与 extern关键字联合使用,这将影响变量的链接属性(to adjust linkage)。

那么,哪些变量可以被声明为thread_local?以下3类都是ok的
命名空间下的全局变量
类的static成员变量
本地变量
下面引用《C++ Concurrency in Action》书中的例子来说明这3种情况:

namespace loacl
{
thread_local int x;  //A thread-local variable at namespace scope
}

class X
{
    static thread_local std::string s; //A thread-local static class data member
};

static thread_local std::string X::s;  //The definition of X::s is required

void foo()
{
    thread_local std::vector<int> v;  //A thread-local local variable
}

既然每个线程都拥有
一份独立的thread_local变量,那么就有2个问题需要考虑:
各线程的thread_local变量是如何初始化的
各线程的thread_local变量在初始化之后拥有怎样的生命周期,特别是被声明为thread_local的本地变量(local variables)
下面的代码可以帮助回答这2个问题,我的测试环境是vs2015。
输出的前3行打印能帮助解答thread_local变量是如何初始化的,可以看到每个线程都会进行一次初始化,例子中的g_n在主线程中最早被初始化为1,随后被修改为2和3,但这些修改操作并不影响g_n在线程t2和t3中的初始值(值为1),虽然t2和t3线程启动的时候主线程中的变量值已经被更新为3,所以主线程、thread1、thread2打印结果分别为3,2,2。
后6行打印说明了一个事实,声明为thread_local的本地变量在线程中是持续存在的,不同于普通临时变量的生命周期,它具有static变量一样的初始化特征和生命周期,虽然它并没有被声明为static。例子中foo函数中的thread_local变量 i 在每个线程第一次执行到的时候初始化,在每个线程各自累加,在线程结束时释放。

#include <thread>

thread_local int g_n = 1;  //声明一个thread线程周期变量 g_n,很重要这个是声明,不是定义

void f()
{
    g_n++;
    printf("id=%d, n=%d\n", std::this_thread::get_id(),g_n);
}

void foo()
{
    thread_local int i=0;
    printf("id=%d, n=%d\n", std::this_thread::get_id(), i);
    i++;
}

void f2()
{
    foo();
    foo();
}

int main()
{
    g_n++;  //主线程使用g_n 变量,这里g_n 才会分配空间,且初始值为1
    f();    //主线程使用g_n 变量
    std::thread t1(f); //t1使用g_n 变量,在t1线程g_n 才会定义分配空间,初始值为1
    std::thread t2(f);
    
    t1.join();
    t2.join();


    f2();
    std::thread t4(f2);
    std::thread t5(f2);

    t4.join();
    t5.join();
    return 0;
}

输出(id值是每次运行时变的):

id=8004, n=3  //主线程
id=8008, n=2  //t1线程,这里说明,t1线程中g_n 不是主线程中的g_n 是t1线程自己的。
id=8012, n=2
id=8004, n=0
id=8004, n=1
id=8016, n=0
id=8016, n=1
id=8020, n=0
id=8020, n=1

附加一个,存储声明声明表, 块表示局部变量,
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值