• c++11~c++20 -05-thread_local


    一、thread_local简介

          thread_local变量是C++ 11新引入的一种存储类型。它会影响变量的存储周期(Storage duration),被thread_local声明的变量在行为上非常像静态变量,只不过多了线程属性。

          在同一个线程中,一个线程局部存储对象只会初始化一次,即使在某个函数中被多次调用,这一点和单线程中的静态对象非常相似。对象的存储在线程开始时分配,相对应的,对象的销毁也只会发生一次,通常发生在线程退出的时刻,接下看几个例子。

          thread_local 只对声明于命名空间作用域的对象、声明于块作用域的对象以及静态数据成员允许。它指示对象拥有线程存储期。它能与 static 或 extern 结合,以分别指定内部或外部链接(除了静态数据成员始终拥有外部链接),但附加的 static 不影响存储期。

    二、示例

    2.1.全局变量

    #include 
    #include 
    
    thread_local int g_nx = 1;
    
    void thread_func(const std::string& thread_name) {
    	for (int i = 0; i < 50; i++) {
    		
    		printf("thread[%s]:g_nx = %d\n", thread_name.c_str(),g_nx);
    		g_nx++;
    	}
    }
    
    int main() {
    	std::thread t1(thread_func, "t1");
    	std::thread t2(thread_func, "t2");
    	t1.join();
    	t2.join();
    	system("pause");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    结果:
    在这里插入图片描述
    从结果可以看出,每个线程各自拷贝了一份数据。
    在这里插入图片描述

    2.2.局部变量

    修改线程函数如下:

    void thread_func(const std::string& thread_name) {
    	for (int i = 0; i < 50; i++) 
    	{
    		thread_local int g_nx = 1;
    		printf("thread[%s]:g_nx = %d\n", thread_name.c_str(),g_nx);
    		g_nx++;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果和“一、全局变量”相同,g_nx只在线程创建的时候执行了一次。那如果换成static,会有什么反应呢?

    void thread_func(const std::string& thread_name) {
    	for (int i = 0; i < 50; i++) 
    	{
    		std::lock_guard<std::mutex> lc(mutexx);
    		static  int g_nx = 1;
    		printf("thread[%s]:g_nx = %d\n", thread_name.c_str(),g_nx);
    		g_nx++;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    2.3.类对象

    class A {
    public:
    	A() {
    		
    		std::cout << "构造函数\n";
    	}
    
    	~A() {
    	
    		std::cout << "析构函数\n";
    	}
    
    	
    	int get_value() 
    	{
    		return counter++;
    	}
    private:
    	int counter = 0;
    };
    
    void thread_func(const std::string& thread_name) {
    	for (int i = 0; i < 3; ++i) 
    	{
    		thread_local std::shared_ptr<A> spA(new A());
    		printf("thread[%s]:a.counter = %d\n", thread_name.c_str(), spA->get_value());
    		
    	}
    	return;
    }
    
    
    int main() 
    {
    	{
    		std::thread t1(thread_func, "t1");
    		std::thread t2(thread_func, "t2");
    		t1.join();
    		t2.join();
    
    	}
    	
    	system("pause");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    结果:
    在这里插入图片描述

    2.4.类成员变量

    thread_local 作为类成员变量时必须是 static 的!

    class A {
    public:
    	A() {
    		
    		std::cout << "构造函数\n";
    	}
    
    	~A() {
    	
    		std::cout << "析构函数\n";
    	}
    
    	static int inline m_sN = 15;
    	static int inline thread_local  m_tlN = 15;
    };
    
    void thread_func(const std::string& thread_name)
    {
    	A a;
    	for (int i = 0; i < 3; ++i) 
    	{
    		a.m_sN--;
    		a.m_tlN--;
    		printf("thread[%s]:m_sN = %d,m_tlN =%d \n", thread_name.c_str(),a.m_sN,a.m_tlN);
    		
    	}
    	return;
    }
    
    
    int main() 
    {
    	{
    		std::thread t1(thread_func, "t1");
    		std::thread t2(thread_func, "t2");
    		t1.join();
    		t2.join();
    
    	}
    	
    	system("pause");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    结果:
    在这里插入图片描述

  • 相关阅读:
    Jenkins+Docker+SVN实现SpringBoot项目半自动化部署
    CentOS 离线升级Linux的内核并删除多有内核
    SpringMvc增删改查
    WPF向Avalonia迁移(三、项目结构)
    asp.net田径运动会管理系统
    Python数据分析案例07——二手车估价(机器学习全流程,数据清洗、特征工程、模型选择、交叉验证、网格搜参、预测储存)
    GBase8s数据库由数据库对象执行的对照
    HelloWorld:通过demo,构建黑盒模型
    Mysql索引
    OpenCV(十):图像缩放、翻转、拼接的介绍与使用
  • 原文地址:https://blog.csdn.net/FairLikeSnow/article/details/126293429