TLS--线程局部存储

 

转自:https://blog.csdn.net/u013761036/article/details/54960277

这个东西并不陌生了,之前写过了一个关于这个的应用,利用静态TLS姿势实现代码段静态加密免杀或者所谓的加壳思路。地址在这:http://blog.csdn.net/u013761036/article/details/53967943今天就简单的整理下TLS的相关概念和常规应用。一开始说了一大堆的Windows的进程与线程啥啥啥的概念和原理,这里直接省略。

什么是线程局部存储?

    线程局部存储(Thread Local Storage,TLS)很好的解决了多线程设计中变量同步问题,比如你写一个exe里面有N个线程,你可以放弃使用TLS,因为你对自己设计的程序有比较全面的把握。你清楚自己设计的进程里总共有多少个线程,每个线程使用了哪些数据结构,内存空间申请、释放都在你的掌控之下,全局变量的访问全部都采用了同步技术,那是没问题的。如果你是一个DLL开发者,你无法确定调用这个DLL的素质程序里到底有多少个线程,每个线程的数据是如何定义的,这时,可以考虑使用线程据存储技术。

 

TLS分为静态和动态两种:

动态TLS,主要是使用这几个API TlsAlloc ,TlsGetValue,TlsSetValue,TlsFree

下面是微软MSDN上的一个例子,看下理解下:

 

 

[cpp] view plain copy

  1. <code class="language-cpp">#include <windows.h>   
  2. #include <stdio.h>   
  3.    
  4. #define THREADCOUNT 4   
  5. DWORD dwTlsIndex;   
  6.    
  7. VOID ErrorExit(LPSTR);   
  8.    
  9. VOID CommonFunc(VOID)   
  10. {   
  11.    LPVOID lpvData;   
  12.    
  13. // Retrieve a data pointer for the current thread.   
  14.    
  15.    lpvData = TlsGetValue(dwTlsIndex);   
  16.    if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS))   
  17.       ErrorExit("TlsGetValue error");   
  18.    
  19. // Use the data stored for the current thread.   
  20.    
  21.    printf("common: thread %d: lpvData=%lx\n",   
  22.       GetCurrentThreadId(), lpvData);   
  23.    
  24.    Sleep(5000);   
  25. }   
  26.    
  27. DWORD WINAPI ThreadFunc(VOID)   
  28. {   
  29.    LPVOID lpvData;   
  30.    
  31. // Initialize the TLS index for this thread.   
  32.    
  33.    lpvData = (LPVOID) LocalAlloc(LPTR, 256);   
  34.    if (! TlsSetValue(dwTlsIndex, lpvData))   
  35.       ErrorExit("TlsSetValue error");   
  36.    
  37.    printf("thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData);   
  38.    
  39.    CommonFunc();   
  40.    
  41. // Release the dynamic memory before the thread returns.   
  42.    
  43.    lpvData = TlsGetValue(dwTlsIndex);   
  44.    if (lpvData != 0)   
  45.       LocalFree((HLOCAL) lpvData);   
  46.    
  47.    return 0;   
  48. }   
  49.    
  50. int main(VOID)   
  51. {   
  52.    DWORD IDThread;   
  53.    HANDLE hThread[THREADCOUNT];   
  54.    int i;   
  55.    
  56. // Allocate a TLS index.   
  57.    
  58.    if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)   
  59.       ErrorExit("TlsAlloc failed");   
  60.    
  61. // Create multiple threads.   
  62.    
  63.    for (i = 0; i < THREADCOUNT; i++)   
  64.    {   
  65.       hThread[i] = CreateThread(NULL, // default security attributes   
  66.          0,                           // use default stack size   
  67.          (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function   
  68.          NULL,                    // no thread function argument   
  69.          0,                       // use default creation flags   
  70.          &IDThread);              // returns thread identifier   
  71.    
  72.    // Check the return value for success.   
  73.       if (hThread[i] == NULL)   
  74.          ErrorExit("CreateThread error\n");   
  75.    }   
  76.    
  77.    for (i = 0; i < THREADCOUNT; i++)   
  78.       WaitForSingleObject(hThread[i], INFINITE);   
  79.    
  80.    TlsFree(dwTlsIndex);  
  81.   
  82.    return 0;   
  83. }   
  84.    
  85. VOID ErrorExit (LPSTR lpszMessage)   
  86. {   
  87.    fprintf(stderr, "%s\n", lpszMessage);   
  88.    ExitProcess(0);   
  89. }</code>  


 

 

 

静态TLS

    静态线程局部存储是操作系统提供的另外一种线程与数据绑定的技术。它与动态TLS的区别在于,通过静态线程局部存储指定的数据无需使用专门的API函数,随意在易用性上会更好一些。

    静态线程局部存储预先将变量定义在PE文件内部,一般使用.tls节存储,对于相关API的调用由操作系统来完成。这种方式的有点就是从高级语言程序员角度来看更简单了。这种实现方式使得TLS数据的定义与初始化就像程序中使用普通的静态变量那样。

    对静态TLS变量的定义不需要想动态线程局部存储一样,调用相关API,只需要做如下声明即可:

_declspec(thread) int tlsFlag=1;

     为了支持这种编程模式。PE中的.tls节会包含一下信息:

初始化数据

用于每个线程初始化和终止的回调函数

TLS索引

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

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

相关文章

小白科普:Netty有什么用?【转载】

优秀文章链接&#xff1a;https://blog.csdn.net/bjweimengshu/article/details/78786315#commentBox

TLS线程局部存储--thread_specific_ptr

大多数函数都不是可重入的。这也就是说在某一个线程已经调用了一个函数时&#xff0c;如果你再调用同一个函数&#xff0c;那么这样是不安全的。一个不可重入的函数通过连续的调用来保存静态变量或者是返回一个指向静态数据的指针。 举例来说&#xff0c;std::strtok就是不可重…

icpc青岛栈

1001-I Count Two Three 题意&#xff1a;给出一个整数n, 找出一个大于等于n的最小整数m, 使得m可以表示为2a3b5c7d。 分析&#xff1a;很好想&#xff0c;因为数据是在1~1e9之间的&#xff0c;所以直接将所有2a3b5c7d的形式且小于1e9的数字打表&#xff0c;然后二分搜索出大于…

互斥锁和条件变量

转自&#xff1a;https://www.jb51.net/article/102764.htm mutex体现的是一种竞争&#xff0c;我离开了&#xff0c;通知你进来。 cond体现的是一种协作&#xff0c;我准备好了&#xff0c;通知你开始吧。 互斥锁一个明显的缺点是它只有两种状态&#xff1a;锁定和非锁定。…

jetty优秀文章转载

地址&#xff1a;https://www.cnblogs.com/yiwangzhibujian/p/5845623.html

UNet详解(转)

Unity Networking&#xff08;UNet&#xff09;函数时序统计和分析 背景和概述 Unity Networking是官方自Unity5.1以来推出的新网络通信解决方案。UNet是非官方但更民间更精简的叫法。 本文需要读者有基础的UNet知识。 了解UNet时序&#xff0c;可以更好更严谨地编写UNet相…

GET和POST两种基本请求方法的区别

转载地址:https://www.cnblogs.com/logsharing/p/8448446.html GET和POST是HTTP请求的两种基本方法&#xff0c;要说它们的区别&#xff0c;接触过WEB开发的人都能说出一二。 最直观的区别就是GET把参数包含在URL中&#xff0c;POST通过request body传递参数。 你可能自己写过…

icpc大连栈

赛时只出了两题 09 10 06卡死了。很烂&#xff0c;没有及时弃疗06&#xff0c;最后得不偿失 丢人。 1001 Different Circle Permutation&#xff08;矩快polya欧拉函数&#xff09; 题目大意&#xff1a;n个座位围成一圈&#xff0c;n个人中挑出若干个人坐下&#xff0c;要求…

Ubuntu14.04 VSCode工程在root下无运行,在非root无法修改配置文件

转自:https://blog.csdn.net/wenyun_kang/article/details/69389784 vscode的配置文件被加上了root权限 把配置文件的root权限去掉就好了 cd ~/.config sudo rm -rf ./Code/ 然后输入密码就好了 猜测原因:vscode在打开的时候需要改动一些配置文件,但是启动的时候发现文件…

jetty优秀文章

地址&#xff1a;http://hbiao68.iteye.com/category/291430

Ubuntu14.04 Apollo 3.5安装

一.安装git lfs 1. 安装crul &#xff1a; curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash 2. 安装 git-lfs&#xff1a; sudo apt-get --yes --force-yes install git-lfs 确保git-lfs正确安装 &#xff1a;git lfs ins…

查询数据库每天更新的数量

select LEFT(FROM_UNIXTIME(pdate),10),count(LEFT(FROM_UNIXTIME(pdate),10)) from tablename where pdate > 1536944461 and pdate < 1539593178 GROUP BY LEFT(FROM_UNIXTIME(pdate),10)

职场那些事

转自&#xff1a;https://www.zhihu.com/question/49209215 1.没有时间观念 任何集体环境中&#xff0c;没有时间观念都是大忌。尤其在职场团队协作过程中&#xff0c;每个人都有自己的位置&#xff0c;每个人的时间都是宝贵的。工作是环环相扣的&#xff0c;因为你的延期导…

顺序表应用4-2:元素位置互换之逆置算法(数据改进)

Problem Description 一个长度为len(1<len<1000000)的顺序表&#xff0c;数据元素的类型为整型&#xff0c;将该表分成两半&#xff0c;前一半有m个元素&#xff0c;后一半有len-m个元素&#xff08;1<m<len)&#xff0c;设计一个时间复杂度为O(N)、空间复杂度为O(…

HtmlUnit优秀文章

博客地址:https://www.cnblogs.com/davidwang456/articles/8693050.html https://blog.csdn.net/anLA_/article/details/50199815

主程成长之路

原文&#xff1a;https://blog.csdn.net/hackmind/article/details/48137233 0x01、技术 1、技术是程序员吃饭的手艺&#xff0c;打磨自己的手艺肯定无可厚非 2、保持对技术的热爱&#xff0c;不断学习&#xff0c;持续编程 3、有敬畏心&#xff0c;明白自己是在做商业项目…

顺序表应用7:最大子段和之分治递归法

Problem Description 给定n(1<n<50000)个整数&#xff08;可能为负数&#xff09;组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]a[i1]…a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0&#xff0c;依此定义&#xff0c;所求的最优值为&#xff1a; Max{…

WebMagic写的网络爬虫优秀文章

博客地址: https://www.cnblogs.com/yanduanduan/p/6527359.html https://www.cnblogs.com/tibit/p/7136762.html https://blog.csdn.net/qq_36251958/article/details/79313035#commentBox

向量内积(点乘)和外积(叉乘)概念及几何意义

向量的内积&#xff08;点乘&#xff09; 定义 概括地说&#xff0c;向量的内积&#xff08;点乘/数量积&#xff09;。对两个向量执行点乘运算&#xff0c;就是对这两个向量对应位一一相乘之后求和的操作&#xff0c;如下所示&#xff0c;对于向量a和向量b&#xff1a; a和b…

SVN分支/合并

转自&#xff1a;https://blog.csdn.net/e3002/article/details/21469437 先说说什么是branch。按照Subversion的说法&#xff0c;一个branch是某个development line&#xff08;通常是主线也即trunk&#xff09;的一个拷贝&#xff0c;见下图&#xff1a; branch存在的意义在…