thread_local变量是C++ 11新引入的一种存储类型。它会影响变量的存储周期(Storage duration),C++中有4种存储周期:

  1. automatic
  2. static
  3. dynamic
  4. thread

有且只有thread_local关键字修饰的变量具有线程周期(thread duration),这些变量(或者说对象)在线程开始的时候被生成(allocated),在线程结束的时候被销毁(deallocated)。并且每 一个线程都拥有一个独立的变量实例(Each thread has its own instance of the object)。thread_local 可以和staticextern关键字联合使用,这将影响变量的链接属性(to adjust linkage)。

那么,哪些变量可以被声明为thread_local?以下3类都是ok的

  1. 命名空间下的全局变量
  2. 类的static成员变量
  3. 本地变量

下面引用《C++ Concurrency in Action》书中的例子来说明这3种情况:

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个问题需要考虑:

  1. 各线程的thread_local变量是如何初始化的
  2. 各线程的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 = ;

void f()
{
    g_n++;
    printf("id=%d, n=%d\n", std::this_thread::get_id(),g_n);
} void foo()
{
    thread_local int i=;
    printf("id=%d, n=%d\n", std::this_thread::get_id(), i);
    i++;
} void f2()
{
    foo();
    foo();
} int main()
{
    g_n++; 
    f();    
    std::thread t1(f);
    std::thread t2(f);
    
    t1.join();
    t2.join();     f2();
    std::thread t4(f2);
    std::thread t5(f2);     t4.join();
    t5.join();
    return ;
}

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

id=8004, n=3

id=8008, n=2
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

thread_local变量的更多相关文章

  1. thread_local变量(转)

    转自:https://www.cnblogs.com/pop-lar/p/5123014.html thread_local变量是C++11新引入的一种存储类型.它会影响变量的存储周期(Storage ...

  2. c/c++ 多线程 thread_local 类型

    多线程 thread_local 类型 thread_local变量是C++ 11新引入的一种存储类型. thread_local关键字修饰的变量具有线程周期(thread duration), 这些 ...

  3. c++11: thread_local

    thread_local变量是C++ 11新引入的一种存储类型.它会影响变量的存储周期(Storage duration),C++中有4种存储周期: automatic static dynamic ...

  4. [c++] Pieces of knowledge

    再系统地学一遍c++,查缺补漏. wchar_t L'a' stored in wchar_t. size of types cout << numeric_limits<doubl ...

  5. C++14介绍

    C++14标准是 ISO/IEC 14882:2014 Information technology -- Programming languages -- C++ 的简称[1]  .在标准正式通过之 ...

  6. C++11 (多线程)并发编程总结

    | 线程 std::thread 创建std::thread,一般会绑定一个底层的线程.若该thread还绑定好函数对象,则即刻将该函数运行于thread的底层线程. 线程相关的很多默认是move语义 ...

  7. Linux 调试: systemtap

    安装与配置 在ubuntu下直接用apt-get install之后不能正常使用,提示缺少调试信息或者编译探测代码时有问题. 1. 采用官网上的解决方法 2. 可以自己重新编译一次内核,然后再手工编译 ...

  8. C++11并发编程个人小结

    thread_local变量在每个线程第一次执行到时初始化(类似static),并在每个线程各自累加,并在线程结束时释放. std::condition_variable:: wait(std::un ...

  9. C++的各种初始化方式

    C++小实验测试:下面程序中main函数里a.a和b.b的输出值是多少? #include <iostream> struct foo { foo() = default; int a; ...

随机推荐

  1. vue 的小秘密

    1.组件可以通过$refs调用其方法. 2.组件上也可用v-model. <input v-model="something"> == 同等 <input v-b ...

  2. linux的文件

    今日感慨:linux根目录下的文件夹含义 bin的知识,二进制文件,其用途依系统或应用而定 . 也就是说,一般来讲是机器代码,汇编语言编译后的结果,(DOS下汇编语言编译后与.com文件相类似),用d ...

  3. C++(十八) — 内存模式、堆和栈

    1.内存模式 一个程序执行时,先复制到内存,然后CPU逐句读取指令执行. 每个存储单元存放一个字节(8bit)数据,每个有一个唯一的地址,地址是顺序编码的.比如:一台计算机256MB内存,则有256* ...

  4. jquery attr与prop的区别与联系

    最近开发中发现用attr无法设置checkbox的选中事件,在网上找了下说要用prop,所以总结下两者的区别. 1.操作的对象不同 attr:操作的是HTML文档节点属性 prop:操作的是js对象属 ...

  5. Ceph中的容量计算与管理

    转自:https://www.ustack.com/blog/ceph%ef%bc%8drongliang/ 在部署完Ceph集群之后,一般地我们可以通过Ceph df这个命令来查看集群的容量状态,但 ...

  6. Redis-sentinel哨兵模式集群方案配置

    一.sentinel介绍 Redis Sentinel Sentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中 Sentinel作用: 1) ...

  7. 018对象——对象 get_class get_declared_classes get_declared_interfaces

    <?php /** * 对象 get_class get_declared_classes get_declared_interfaces */ //get_class() 获得对象的类名,区分 ...

  8. LeetCode OJ:Search a 2D Matrix(二维数组查找)

    Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the follo ...

  9. android实现log日志输出

    1.下载android的log4j的库(的封装) 去: http://code.google.com/p/android-logging-log4j/ 下载对应的 android-logging-lo ...

  10. Oracle中的填充函数lpad和rpad的用法(转)

    原文链接:http://blog.csdn.net/myzhanglt/article/details/7392999 今日学习遇到一个不熟悉的函数LPAD,查了一下文档,将其用法总结如下: Lpad ...