C++新特性 线程局部存储

本篇文章来介绍一下关于线程局部存储的一些概念

线程局部存储(Thread Local Storage,TLS)是一种编程技术,用于为每个线程提供独立的变量副本。它允许在多线程程序中创建全局变量的多个实例,每个实例都与特定的线程相关联。

传统上,全局变量是所有线程共享的,在并发环境下可能导致竞态条件和数据访问冲突。而通过使用线程局部存储,可以使每个线程都拥有自己独立的变量副本,从而避免了竞态条件问题。

线程局部存储通常用于以下情况:

  1. 线程特定数据:某些数据只对特定线程有意义,并且需要在线程内保持状态。
  2. 全局状态隔离:将全局状态分离为每个线程的私有副本,以提高并发性能。
  3. 线程上下文保存:将当前执行线程的上下文信息保存在特定于该线程的变量中。

在C++中,可以使用thread_local关键字来声明具有线程局部存储语义的变量。这样声明的变量将为每个执行线程维护一个独立的副本。

以下是代码实例:

#include <iostream>
#include <thread>thread_local int tls_variable = 0;void thread_function() {tls_variable += 1;std::cout << "Thread ID: " << std::this_thread::get_id() << ", TLS variable: " << tls_variable << std::endl;
}int main() {std::thread t1(thread_function);std::thread t2(thread_function);t1.join();t2.join();return 0;
}

上述示例中,每个线程都有自己独立的tls_variable副本。在线程函数内部,对该变量的修改只会影响到当前线程的副本。输出结果将显示每个线程对变量进行递增操作后的值。

需要注意的是,TLS仅在C++11及以上版本中可用,并且只能用于具有静态或线程存储期的变量,不能用于自动或动态分配的变量。

windows线程存储API:

在Windows平台上,可以使用以下API来实现线程局部存储(Thread Local Storage):

  1. TlsAlloc:用于分配一个TLS索引,返回一个TLS索引值。该索引将用作线程特定数据的唯一标识符。

  2. TlsFree:释放先前分配的TLS索引。

  3. TlsSetValue:设置当前线程中与给定TLS索引相关联的值。

  4. TlsGetValue:获取当前线程中与给定TLS索引相关联的值。

这四个函数的综合使用代码实例:

#include <iostream>
#include <windows.h>DWORD tlsIndex;  // 全局变量用于保存TLS索引void ThreadFunction() {int* threadData = new int(42);TlsSetValue(tlsIndex, threadData);  // 将线程特定数据存储到TLS中int* retrievedData = static_cast<int*>(TlsGetValue(tlsIndex));  // 从TLS中获取线程特定数据std::cout << "Thread ID: " << GetCurrentThreadId()<< ", Thread-specific data: " << *retrievedData << std::endl;delete retrievedData;  // 释放内存
}int main() {tlsIndex = TlsAlloc();  // 分配一个新的TLS索引if (tlsIndex == TLS_OUT_OF_INDEXES) {std::cerr << "Failed to allocate TLS index." << std::endl;return -1;}std::thread t1(ThreadFunction);std::thread t2(ThreadFunction);t1.join();t2.join();TlsFree(tlsIndex);  // 释放TLS索引return 0;
}

在上述示例中,使用TlsAlloc函数分配一个新的TLS索引,然后在每个线程的函数中使用TlsSetValue将线程特定数据存储到TLS中。在主函数中,创建两个线程,并通过调用TlsGetValue来检索并输出线程特定数据。最后,使用TlsFree释放TLS索引。

需要注意的是,上述代码仅为演示目的,并未考虑异常处理和内存泄漏等问题。实际应用中,请根据具体需求进行合适的错误处理和资源管理。

linux中完成线程局部存储的任务函数

在Linux中,可以使用线程局部存储(Thread Local Storage,TLS)来实现线程特定的数据。

#include <iostream>
#include <pthread.h>// 定义线程局部数据键
pthread_key_t tls_key;// 线程退出时的清理函数
void cleanup(void* value) {std::cout << "Cleaning up thread-local data: " << *(int*)value << std::endl;delete (int*)value;
}// 线程函数
void* thread_func(void* arg) {// 创建一个动态分配的整数,并将其存储到线程局部存储中int* value = new int(42);pthread_setspecific(tls_key, value);// 获取线程局部存储中的值,并打印出来std::cout << "Thread-local value: " << *(int*)pthread_getspecific(tls_key) << std::endl;return nullptr;
}int main() {// 创建线程局部数据键pthread_key_create(&tls_key, cleanup);// 创建多个线程并运行const int num_threads = 3;pthread_t threads[num_threads];for (int i = 0; i < num_threads; ++i) {pthread_create(&threads[i], nullptr, thread_func, nullptr);}// 等待所有线程结束并回收资源for (int i = 0; i < num_threads; ++i) {pthread_join(threads[i], nullptr);}// 销毁线程局部数据键pthread_key_delete(tls_key);return 0;
}

这段代码创建了一个线程局部存储键 tls_key并在每个线程中将不同的整数值存储到线程局部存储中。当每个线程结束时,会调用清理函数 cleanup 来释放动态分配的内存。

请注意,在编译时需要链接 pthread 库(使用 -lpthread 参数)。

linux实现线程存储的总结:

在Linux中,可以使用线程局部存储(Thread Local Storage,TLS)来实现线程特定的数据。以下是对线程局部任务存储函数的总结:

  1. 首先,需要包含头文件 pthread.h

  2. 使用 pthread_key_t 类型定义一个线程局部数据键。

  3. 定义一个清理函数,在线程退出时调用该函数来释放分配的内存。清理函数的参数类型为 void*

  4. 在主函数或其他适当位置创建线程局部数据键,使用 pthread_key_create() 函数。该函数接受两个参数:指向 pthread_key_t 的指针和清理函数指针。

  5. 创建并运行多个线程。在线程函数中,使用 pthread_setspecific() 函数将要存储的值与键关联起来。该函数接受两个参数:线程局部数据键和要存储的值。

  6. 若要访问已存储在线程局部存储中的值,可以使用 pthread_getspecific() 函数,并传入相应的线程局部数据键作为参数。

  7. 线程结束后,在清理函数中释放动态分配的内存或执行其他必要操作。

  8. 最后,在程序结束前或合适的地方销毁线程局部数据键,使用 pthread_key_delete() 函数进行销毁。

请注意,在编译时需要链接 pthread 库(使用 -lpthread 参数)。

这样就完成了在Linux上使用线程局部存储函数的过程。

好了本篇文章就描述到这里了 在这里小编想给大家推荐一个课程:

https://xxetb.xetslk.com/s/2PjJ3T

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/665563.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营|day24

第七章 回溯算法 77.组合代码随想录文章详解总结 77.组合 以n5,k3为例 (1)for循环遍历&#xff0c;递归选择符合要求的值加入path&#xff0c;len(path)k时&#xff0c;返回 statrtIndex保证每次递归取到的值不重复 剪枝&#xff1a;i<n-(k-len(path))1 后续需要k-len(pat…

政安晨的AI笔记——示例演绎OpenAI的ChatGPT与DALL·E提示词总原则(并融合创作一副敦煌飞天仙女图)

ChatGPT是由OpenAI开发的一种基于大规模预训练的语言生成模型。它建立在GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型的基础上&#xff0c;通过大量的无监督学习和生成式任务训练来学习语言的概念和模式。 ChatGPT的原理是基于Transformer模型。Transfo…

shell命令以及运行原理 | 权限

Shell命令原理剖析 shell命令以及运行原理&#x1f4a6;Linux权限的概念&#x1f4a6;什么是权限❔Linux下有哪些权限身份❔Linux中文件属性解析 shell命令以及运行原理&#x1f4a6; Linux严格意义上说的是一个操作系统&#xff0c;我们称之为 “核心&#xff08;kernel"…

AS-V1000 视频监控平台产品介绍:客户端功能介绍(一)

目 录 一、引言 1.1 AS-V1000视频监控平台介绍 1.2平台服务器配置说明 二、软件概述 2.1 客户端软件用途 2.2 客户端功能 三、客户端功能说明 3.1 登陆和主界面 3.1.1登陆界面 3.1.2登陆操作 3.1.3主界面 3.1.4资源树 3.2 视频预览 3.2.1视频预览界面 3.2.…

京东微前端框架MicroApp简介

一、MicroApp 1.1 MicroApp简介 MicroApp是由京东前端团队推出的一款微前端框架,它从组件化的思维,基于类WebComponent进行微前端的渲染,旨在降低上手难度、提升工作效率。MicroApp无关技术栈,也不和业务绑定,可以用于任何前端框架。 官网链接:https://micro-zoe.gith…

获取真实 IP 地址(一):判断是否使用 CDN(附链接)

一、介绍 CDN&#xff0c;全称为内容分发网络&#xff08;Content Delivery Network&#xff09;&#xff0c;是一种网络架构&#xff0c;旨在提高用户对于网络上内容的访问速度和性能。CDN通过在全球各地部署分布式服务器节点来存储和分发静态和动态内容&#xff0c;从而减少…

【Linux系统化学习】进程替换

目录 进程程序替换 替换原理 ​编辑替换函数 函数解释 命名理解 函数使用 execl execlp execv execvp 调用其它程序 进程程序替换 替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个…

uboot 模拟 pc BIOS的 跑码诊断

/* * armboot - Startup Code for ARM920 CPU-core * * Copyright (c) 2001 Marius Gr鰃er <magsysgo.de> * Copyright (c) 2002 Alex Z黳ke <azusysgo.de> * Copyright (c) 2002 Gary Jennejohn <garyjdenx.de> * * See file CREDITS f…

禁止 ios H5 中 bounces 滑动回弹效果

在开发面向 iOS 设备的 HTML5 应用时&#xff0c;控制页面的滚动行为至关重要&#xff0c;特别是禁用在 Safari 中默认的滑动回弹效果。本文旨在提供一个简洁明了的解决方案&#xff0c;帮助开发者在特定的 Web 应用中禁用这一效果。 1. 什么是滑动回弹效果&#xff1f; 在 iO…

C++输出地址

下面是一段输出地址的程序。 #include <bits/stdc.h> using namespace std;int main() {int s;cout << &s;//原地址return 0; }假如有一个人&#xff08;的朋友&#xff09;后来了&#xff0c;他也想住进的房间&#xff0c;我们可以这样&#xff1a; #includ…

从ORA-00283 ORA-16433报错开始恢复---惜分飞

接手一个客户无法正常启动的故障数据库&#xff0c;尝试recover 报ORA-00283 ORA-16433错误 [oraclexff trace]$ sqlplus / as sysdba SQL*Plus: Release 12.1.0.2.0 Production on Sat Jan 27 04:46:23 2024 Copyright (c) 1982, 2014, Oracle. All rights reserved. ??…

docker 运行jar包

要在Docker中运行JAR包&#xff0c;你可以使用以下步骤&#xff1a; 创建一个Dockerfile&#xff0c;指定基础镜像和设置工作目录。例如&#xff1a; # 使用官方Java镜像作为基础镜像 FROM openjdk:8-jdk-alpine# 设置工作目录 WORKDIR /app 将JAR包复制到容器中的/app目录。…

【数据结构】链表OJ面试题2(题库+解析)

1.前言 前五题在这http://t.csdnimg.cn/UeggB 休息一天&#xff0c;今天继续刷题&#xff01; 2.OJ题目训练 1. 编写代码&#xff0c;以给定值x为基准将链表分割成两部分&#xff0c;所有小于x的结点排在大于或等于x的结点之前 。链表分割_牛客题霸_牛客网 思路 既然涉及…

gif动图的裁剪实现思路

项目需求(对app的轮播,以及banner和咨询的图片进行裁剪):前期实现使用用vue-cropper插件对图片进行插件,----后续需求需要裁剪gif动图(vue-cropper、微信自带的截图工具,以及fastStone截图工具,都只能截取静态图片,打开动图时只显示某一帧的静态图片),所以需要研究为什么vue-cr…

JAVASE进阶:函数式编程——lambda表达式替代匿名内部类

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;JAVASE进阶&#xff1a;强推&#xff01;源码分析——字符串拼接底层原理、StringBuilder底层原理 &#x1f4da;订阅专栏&#…

机器学习——集成学习

&#x1f4d5;参考&#xff1a;ysu老师课件西瓜书 期末复习笔记 1.集成学习的基本概念 集成学习&#xff08;ensemble learing&#xff09;通过构建并结合多个学习器来完成学习任务。 有时也被称为多分类器系统&#xff08;multi-classifier system&#xff09;、基于委员会的…

Spring Cloud Stream解密:流式数据在微服务中的魔力

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Spring Cloud Stream解密&#xff1a;流式数据在微服务中的魔力 前言Spring Cloud Stream基础&#xff1a;微服务中的数据流动Binder概念与使用&#xff1a;连接流的音符消息序列化与反序列化&#xf…

开源社区的力量:共同构建数字时代的未来(AI)

开源社区的力量&#xff1a;共同构建数字时代的未来 引言开源社区的定义与发展历程 1. 开源社区的定义2. 发展历程 开源社区的核心价值 1. 技术共享与创新2. 协作与社区建设3. 自由开放的精神 开源社区对数字时代的贡献 1. 技术创新的推动者2. 开放式标准的制定者3. 教育和培训…

【消息队列】kafka整理

kafka整理 整理kafka基本知识供回顾。

Leetcode刷题笔记题解(C++):99. 恢复二叉搜索树

思路&#xff1a; 二叉搜索树的中序遍历是递增序列&#xff0c;可以在中序遍历中记录两个需要交换的节点&#xff0c;直到遍历完毕之后&#xff0c;对两个节点的值进行交换即可得到正确的二叉搜索树 比如中序序列为 1 2 3 7 5 6 4&#xff08;7比5大记录7为x&#xf…