当前位置: 首页 > news >正文

2013我国中小企业接入互联网和网站建设情况/百度百家官网入口

2013我国中小企业接入互联网和网站建设情况,百度百家官网入口,iis网站配置 无法浏览,wordpress和主题Thread local storage (TLS)统一进程的多个线程可以通过由TlsAlloc方法返回的索引值在线程自身的空间内存储和取回一个值。在以下这个例子里,索引值在进程开始时创建,当各个线程启动时,会各自申请一块动态内存并且将内存指针通过TlsSetValue方…

Thread local storage (TLS)统一进程的多个线程可以通过由TlsAlloc方法返回的索引值在线程自身的空间内存储和取回一个值。在以下这个例子里,索引值在进程开始时创建,当各个线程启动时,会各自申请一块动态内存并且将内存指针通过TlsSetValue方法存储到各自的TLS空间中(由先前的索引值标定)。CommonFunc方法使用TlsGetValue方法通过索引取得数据指针。在各个线程结束前,释放动态内存块。在进程结束见,调用TlsFree方法释放索引。

 1#include <windows.h> 
 2#include <stdio.h> 
 3 
 4#define THREADCOUNT 4 
 5DWORD dwTlsIndex; 
 6 
 7VOID ErrorExit(LPSTR); 
 8 
 9VOID 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 
27DWORD 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 
50int 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 
85VOID ErrorExit (LPSTR lpszMessage) 
86
87   fprintf(stderr, "%s\n", lpszMessage); 
88   ExitProcess(0); 
89}

90

常用情景:
各个线程所处理的对象有所不同,但是所需要的处理却可能类似,例如多个线程同时处理多个文件,就可以将文件句柄存在在相应的Tls中,在使用相同的接口进行处理
背景知识:
每个线程除了共享进程的资源外还拥有各自的私有资源:一个寄存器组(或者说是线程上下文);一个专属的堆栈;一个专属的消息队列;一个专属的Thread Local Storage(TLS);一个专属的结构化异常处理串链。
TLS 是一个良好的Win32 特质,让多线程程序设计更容易一些。TLS 是一个机制,经由它,程序可以拥有全域变量,但在不同的线程里有不同的值。也就是说,进程中的所有线程都可以拥有全域变量,但这些变量其实是特定对某个线程才有意义。例如,你可能有一个多线程程序,每一个线程都对不同的文件写文件(也因此它们使用不同的文件handle)。这种情况下,把每一个线程所使用的文件handle 储存在TLS 中,将会十分方便。当线程需要知道所使用的handle,它可以从TLS 获得。重点在于:线程用来取得文件handle 的那一段码在任何情况下都是相同的,而从TLS中取出的文件handle 却各不相同。非常灵巧,不是吗?有全域变数的便利,却又分属各线程。

 

  虽然TLS 很方便,它并不是毫无限制。在Windows NT 和Windows 95 之中,有64 个DWORD slots 供每一个线程使用。这意思是一个进程最多可以有64 个「对各线程有不同意义」的DWORDs。 虽然TLS 可以存放单一数值如文件handle,更常的用途是放置指针,指向线程的私有资料。有许多情况,多线程程序需要储存一堆数据,而它们又都是与各线程相关。许多程序员对此的作法是把这些变量包装为C 结构,然后把结构指针储存在TLS 中。当新的线程诞生,程序就配置一些内存给该结构使用,并且把指针储存在为线程保留下来的TLS 中。一旦线程结束,程序代码就释放所有配置来的区块。既然每一个线程都有64 个slots 用来储存线程自己的数据,那么这些空间到底打哪儿来?在线程的学习中我们可以从结构TDB中看到,每一个thread database 都有64 个DWORDs 给TLS 使用。当你以TLS 函式设定或取出数据,事实上你真正面对的就是那64 DWORDs。好,现在我们知道了原来那些“对各线程有不同意义的全局变量”是存放在线程各自的TDB中阿。
 
    接下来你也许会问:我怎么存取这64个DWORDS呢?我又怎么知道哪个DWORDS被占用了,哪个没有被占用呢?首先我们要理解这样一个事实:系统之所以给我们提供TLS这一功能,就是为了方便的实现“对各线程有不同意义的全局变量”这一功能;既然要达到“全局变量”的效果,那么也就是说每个线程都要用到这个变量,既然这样那么我们就不需要对每个线程的那64个DWORDS的占用情况分别标记了,因为那64个DWORDS中的某一个一旦占用,是所有线程的那个DWORD都被占用了,于是KERNEL32 使用两个DWORDs(总共64 个位)来记录哪一个slot 是可用的、哪一个slot 已经被用。这两个DWORDs 可想象成为一个64 位数组,如果某个位设立,就表示它对应的TLS slot 已被使用。这64 位TLS slot 数组存放在process database 中(在进程一节中的PDB结构中我们列出了那两个DWORDs)。
 
下面的四个函数就是对TLS进行操作的:

  (1)TlsAlloc  

上面我们说过了KERNEL32 使用两个DWORDs(总共64 个位)来记录哪一个slot 是可用的、哪一个slot 已经被用。当你需要使用一个TLS slot 的时候,你就可以用这个函数将相应的TLS slot位置1。 

 (2)TlsSetValue  

TlsSetValue 可以把数据放入先前配置到的TLS slot 中。两个参数分别是TLS slot 索引值以及欲写入的数据内容。TlsSetValue 就把你指定的数据放入64 DWORDs 所组成的数组(位于目前的thread database)的适当位置中。  

 (3)TlsGetValue  

这个函数几乎是TlsSetValue 的一面镜子,最大的差异是它取出数据而非设定数据。和TlsSetValue 一样,这个函数也是先检查TLS 索引值合法与否。如果是,TlsGetValue 就使用这个索引值找到64 DWORDs 数组(位于thread database 中)的对应数据项,并将其内容传回。  

 (4)TlsFree  

这个函数将TlsAlloc 和TlsSetValue 的努力全部抹消掉。TlsFree 先检验你交给它的索引值是否的确被配置过。如果是,它将对应的64 位TLS slots 位关闭。然后,为了避免那个已经不再合法的内容被使用,TlsFree 巡访进程中的每一个线程,把0 放到刚刚被释放的那个TLS slot 上头。于是呢,如果有某个TLS 索引后来又被重新配置,所有用到该索引的线程就保证会取回一个0 值,除非它们再调用TlsSetValue。

 

From:http://www.cppblog.com/dawnbreak/articles/68027.html

 

很多时候,开发者在编写多线程程序的时候都希望存储一些线程私有的数据。我们知道,属于每个线程私有的数据包括线程的栈和当前的寄存器,但是这两种存储都是非常不可靠的,栈会在每个函数退出和进入的时候被改变;而寄存器更是少得可怜,我们不可能拿寄存器去存储所需要的数据。假设我们要在线程中使用一个全局变量,但希望这个全局变量是线程私有的,而不是所有线程共享的,该怎么办呢?这时候就须要用到线程局部存储(TLS,Thread Local Storage)这个机制了。TLS的用法很简单,如果要定义一个全局变量为TLS类型的,只需要在它定义前加上相应的关键字即可。对于GCC来说,这个关键字就是__thread,比如我们定义一个TLS的全局整型变量:

 

__thread int number;

对于MSVC来说,相应的关键字为__declspec(thread):

__declspec(thread) int number;

 

在Windows Vista和2008之前的操作系统,如果TLS的全局变量被定义在一个DLL中,并且该DLL是使用LoadLibrary()显式装载的,那么该全局变量将无法使用,如果访问该全局变量将会导致程序发生保护错误。导致这个情况的主要原因是在Windows Vista之前的操作系统下,DLL在使用LoadLibrary()装载时无法正确初始化由__declspec(thread)定义的变量,具体请参照MSDN。

一旦一个全局变量被定义成TLS类型的,那么每个线程都会拥有这个变量的一个副本,任何线程对该变量的修改都不会影响其他线程中该变量的副本。

Windows TLS的实现

对于Windows系统来说,正常情况下一个全局变量或静态变量会被放到".data"或".bss"段中,但当我们使用__declspec(thread)定义一个线程私有变量的时候,编译器会把这些变量放到PE文件的".tls"段中。当系统启动一个新的线程时,它会从进程的堆中分配一块足够大小的空间,然后把".tls"段中的内容复制到这块空间中,于是每个线程都有自己独立的一个".tls"副本。所以对于用__declspec(thread)定义的同一个变量,它们在不同线程中的地址都是不一样的。

我们知道对于一个TLS变量来说,它有可能是一个C++的全局对象,那么每个线程在启动时不仅仅是复制".tls"的内容那么简单,还需要把这些TLS对象初始化,必须逐个地调用它们的全局构造函数,而且当线程退出时,还要逐个地将它们析构,正如普通的全局对象在进程启动和退出时都要构造、析构一样。

Windows PE文件的结构中有个叫数据目录的结构,我们在第2部分已经介绍过了。它总共有16个元素,其中有一元素下标为IMAGE_DIRECT_ENTRY_TLS,这个元素中保存的地址和长度就是TLS表(IMAGE_TLS_DIRECTORY结构)的地址和长度。TLS表中保存了所有TLS变量的构造函数和析构函数的地址,Windows系统就是根据TLS表中的内容,在每次线程启动或退出时对TLS变量进行构造和析构。TLS表本身往往位于PE文件的".rdata"段中。

另外一个问题是,既然同一个TLS变量对于每个线程来说它们的地址都不一样,那么线程是如何访问这些变量的呢?其实对于每个Windows线程来说,系统都会建立一个关于线程信息的结构,叫做线程环境块(TEB,Thread Environment Block)。这个结构里面保存的是线程的堆栈地址、线程ID等相关信息,其中有一个域是一个TLS数组,它在TEB中的偏移是0x2C。对于每个线程来说,x86的FS段寄存器所指的段就是该线程的TEB,于是要得到一个线程的TLS数组的地址就可以通过FS:[0x2C]访问到。

TEB这个结构不是公开的,它可能随着Windows版本的变化而变化,我们这里所说的TEB结构都是指在x86版的Windows XP。

这个TLS数组对于每个线程来说大小是固定的,一般有64个元素。而TLS数组的第一个元素就是指向该线程的".tls"副本的地址。于是要得到一个TLS的变量地址的步骤为:首先通过FS:[0x2C]得到TLS数组的地址,然后根据TLS数组的地址得到".tls"副本的地址,然后加上变量在".tls"段中的偏移即该TLS变量在线程中的地址。下面看一个简单的例子:

 

__declspec(thread) int t = 1;
int main()
{
t = 2;
return 0;
}

经过编译以后,这段代码的汇编实现如下:

_main:
00000000: 55                 push        ebp
00000001: 8B EC              mov         ebp,esp
00000003: A1 00 00 00 00     mov         eax,dword ptr [__tls_index]
00000008: 64 8B 0D 00 00 00  mov         ecx,dword ptr fs:[__tls_array]
00
0000000F: 8B 14 81           mov         edx,dword ptr [ecx+eax*4]
00000012: C7 82 00 00 00 00  mov         dword ptr _t[edx],2
02 00 00 00
0000001C: 33 C0              xor         eax,eax
0000001E: 5D                 pop         ebp
0000001F: C3                 ret

 

代码中有两个符号__tls_index和__tls_array,它们被定义在MSVC CRT中,对于MSVC 2008来说,它们的值分别是0和0x2C,分别表示TLS数组下的第一个元素和TLS数组在TEB中的偏移。由于这两个数值有可能随着Windows系统的变化而变化,所以它们被保存在CRT中,如果程序以DLL方式链接,那么在不同版本的Windows平台上运行就不会有问题;如果是静态链接,那么当新版的Windows更改TEB结构时而导致TLS数组在TEB中的偏移改变,程序运行就可能出错。当然出于Windows多年来的"良好表现",这种随意更改核心数据结构的事情发生的可能性还是比较小的。

显式TLS

前面提到的使用__thread或__declspec(thread)关键字定义全局变量为TLS变量的方法往往被称为隐式TLS,即程序员无须关心TLS变量的申请、分配赋值和释放,编译器、运行库还有操作系统已经将这一切悄悄处理妥当了。在程序员看来,TLS全局变量就是线程私有的全局变量。相对于隐式TLS,还有一种叫做显式TLS的方法,这种方法是程序员须要手工申请TLS变量,并且每次访问该变量时都要调用相应的函数得到变量的地址,并且在访问完成之后需要释放该变量。在Windows平台上,系统提供了TlsAlloc()、TlsGetValue()、TlsSetValue()和TlsFree()这4个API函数用于显式TLS变量的申请、取值、赋值和释放;Linux下相对应的库函数为pthread库中的pthread_key_create()、pthread_getspecific()、pthread_setspecific()和pthread_key_delete()。

显式的TLS实现其实非常简单,我们前面提到过TEB结构中有个TLS数组。实际上显式的TLS就是使用这个数组保存TLS数据的。由于TLS数组的元素数量固定,一般是64个,于是显式TLS在实现时如果发现该数组已经被使用完了,就会额外申请4096个字节作为二级TLS数组,使得在WindowsXP下最多能拥有1088(1024+64)个显式TLS变量(当然隐式的TLS也会占用TLS数组)。相对于隐式的TLS变量,显式的TLS变量的使用十分麻烦,而且有诸多限制,显式TLS的诸多缺点已经使得它越来越不受欢迎了,我们并不推荐使用它。

 

From:http://book.51cto.com/art/200904/121072.htm

 

 

 

http://www.lbrq.cn/news/1440181.html

相关文章:

  • 徐州企业免费建站/竞价排名适合百度吗
  • 做摘抄的网站/广州今日刚刚发生的新闻
  • 宁波网站制作首荐荣盛网络好/以下属于网站seo的内容是
  • 设计素材网站上的素材可以商用吗/成都高新seo
  • 公司网站建设需求书/人民日报今日新闻
  • 帝国做网站是选择静态还是伪静态/建站系统源码
  • b2b电子商务平台登录/女装标题优化关键词
  • 手机网站建设服务电话/360优化大师官方下载手机
  • 网站建设实施/能让网络非常流畅的软件
  • 温州知名网站推广/站长工具网站
  • 游戏网站上做银商为赌博人员/成都比较靠谱的seo
  • 做网站推广每天加班/站长工具官网域名查询
  • wordpress 做购物网站/百度知道灰色词代发收录
  • 男朋友说是做竞彩网站维护的/b站引流推广网站
  • 建设景区网站推文/整合营销策略
  • 亿网行网站建设/网络优化工程师有前途吗
  • 网站为什么维护/朝阳区seo搜索引擎优化怎么样
  • wordpress nextgen gallery/网站seo提升
  • wordpress响应多少才正常/兰州seo优化
  • 太原网站优化教程/百度网站首页提交入口
  • 企业网站建设 建立作用/做网站企业
  • 合肥专业网站建设/简述如何对网站进行推广
  • 石家庄上门足疗/网站seo优化方案
  • 深圳网络seo优化/网站需要怎么优化比较好
  • 品牌网站建设仁術大蝌蚪/百度seo官方网站
  • 观澜网站建设/网站seo优化运营
  • 什么网站可以做实验室/精准ip地址查询工具
  • 抖音小程序推广怎么挂才有收益/哈尔滨关键词优化报价
  • 柳州网站建设33/大地seo视频
  • 辽宁城乡建设工程招标网(官网)/网站seo关键词优化技巧
  • 面试实战 问题二十九 Java 值传递与引用传递的区别详解
  • 《AVL树的原理与C++实现:详解平衡二叉搜索树的高效构建与操作》
  • HarmonyOS NDK的JavaScript/TypeScript与C++交互机制
  • VGG改进(2):基于Local Attention的模型优化
  • Java进阶学习之不可变集合
  • 飞算 JavaAI -智慧城市项目实践:从交通协同到应急响应的全链路技术革新