精华内容
下载资源
问答
  • 线程局部存储

    2008-03-28 11:14:00
    线程局部存储
    展开全文
  • 线程局部存储

    千次阅读 2008-03-21 16:08:00
    线程局部存储(thread-local storage, TLS)是一个使用很方便的存储线程局部数据的系统。利用TLS机制可以为进程中所有的线程关联若干个数据,各个线程通过由TLS分配的全局索引来访问与自己关联的数据。这样,每个...

    线程局部存储(thread-local storage, TLS)是一个使用很方便的存储线程局部数据的系统。利用TLS机制可以为进程中所有的线程关联若干个数据,各个线程通过由TLS分配的全局索引来访问与自己关联的数据。这样,每个线程都可以有线程局部的静态存储数据。

    用于管理TLS的数据结构是很简单的,Windows仅为系统中的每一个进程维护一个位数组,再为该进程中的每一个线程申请一个同样长度的数组空间,如图3.9所示。

    图3.9 TSL机制在内部使用的数据结构

    运行在系统中的每一个进程都有图3.9所示的一个位数组。位数组的成员是一个标志,每个标志的值被设为FREE或INUSE,指示了此标志对应的数组索引是否在使用中。Windodws保证至少有TLS_MINIMUM_AVAILABLE(定义在WinNT.h文件中)个标志位可用。

    动态使用TLS的典型步骤如下。

    (1)主线程调用TlsAlloc函数为线程局部存储分配索引,函数原型为:

    DWORD TlsAlloc(void); // 返回一个TLS索引

    如上所述,系统为每一个进程都维护着一个长度为TLS_MINIMUM_AVAILABLE的位数组,TlsAlloc的返回值就是数组的一个下标(索引)。这个位数组的惟一用途就是记忆哪一个下标在使用中。初始状态下,此位数组成员的值都是FREE,表示未被使用。当调用TlsAlloc的时候,系统会挨个检查这个数组中成员的值,直到找到一个值为FREE的成员。把找到的成员的值由FREE改为INUSE后,TlsAlloc函数返回该成员的索引。如果不能找到一个值为FREE的成员,TlsAlloc函数就返回TLS_OUT_OF_INDEXES(在WinBase.h文件中定义为-1),意味着失败。

    例如,在第一次调用TlsAlloc的时候,系统发现位数组中第一个成员的值是FREE,它就将此成员的值改为INUSE,然后返回0。

    当一个线程被创建时,Windows就会在进程地址空间中为该线程分配一个长度为TLS_MINIMUM_AVAILABLE的数组,数组成员的值都被初始化为0。在内部,系统将此数组与该线程关联起来,保证只能在该线程中访问此数组中的数据。如图3.7所示,每个线程都有它自己的数组,数组成员可以存储任何数据。

    (2)每个线程调用TlsSetValue和TlsGetValue设置或读取线程数组中的值,函数原型为:

    BOOL TlsSetValue(

    DWORD dwTlsIndex,     // TLS 索引

    LPVOID lpTlsValue                   // 要设置的值

    );

    LPVOID TlsGetValue(DWORD dwTlsIndex );       // TLS索引

    TlsSetValue函数将参数lpTlsValue指定的值放入索引为dwTlsIndex的线程数组成员中。这样,lpTlsValue的值就与调用TlsSetValue函数的线程关联了起来。此函数调用成功,会返回TRUE。

    调用TlsSetValue函数,一个线程只能改变自己线程数组中成员的值,而没有办法为另一个线程设置TLS值。到现在为止,将数据从一个线程传到另一个线程的惟一方法是在创建线程时使用线程函数的参数。

    TlsGetValue函数的作用是取得线程数组中索引为dwTlsIndex的成员的值。

    TlsSetValue和TlsGetValue分别用于设置和取得线程数组中的特定成员的值,而它们使用的索引就是TlsAlloc函数的返回值。这就充分说明了进程中惟一的位数组和各线程数组的关系。例如,TlsAlloc返回3,那就说明索引3被此进程中的每一个正在运行的和以后要被创建的线程保存起来,用以访问各自线程数组中对应的成员的值。

    (3)主线程调用TlsFree释放局部存储索引。函数的惟一参数是TlsAlloc返回的索引。

    利用TLS可以给特定的线程关联一个数据。比如下面的例子将每个线程的创建时间与该线程关联了起来,这样,在线程终止的时候就可以得到线程的生命周期。整个跟踪线程运行时间的例子的代码如下:

    #include <stdio.h>                                   // 03UseTLS工程下

    #include <windows.h>            

    #include <process.h>

    // 利用TLS跟踪线程的运行时间

    DWORD g_tlsUsedTime;

    void InitStartTime();

    DWORD GetUsedTime();

    UINT __stdcall ThreadFunc(LPVOID)

    {       int i;

             // 初始化开始时间

             InitStartTime();

             // 模拟长时间工作

             i = 10000*10000;

             while(i--){}

             // 打印出本线程运行的时间

             printf(" This thread is coming to end. Thread ID: %-5d, Used Time: %d /n",

                                                                                                           ::GetCurrentThreadId(), GetUsedTime());

             return 0;

    }

    int main(int argc, char* argv[])

    {       UINT uId;

             int i;

             HANDLE h[10];

             // 通过在进程位数组中申请一个索引,初始化线程运行时间记录系统

             g_tlsUsedTime = ::TlsAlloc();

             // 令十个线程同时运行,并等待它们各自的输出结果

             for(i=0; i<10; i++)

             {       h[i] = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &uId);         }

             for(i=0; i<10; i++)

             {       ::WaitForSingleObject(h[i], INFINITE);

                       ::CloseHandle(h[i]);      }

             // 通过释放线程局部存储索引,释放时间记录系统占用的资源

             ::TlsFree(g_tlsUsedTime);

             return 0;

    }

    // 初始化线程的开始时间

    void InitStartTime()

    {       // 获得当前时间,将线程的创建时间与线程对象相关联

             DWORD dwStart = ::GetTickCount();

             ::TlsSetValue(g_tlsUsedTime, (LPVOID)dwStart);

    }

    // 取得一个线程已经运行的时间

    DWORD GetUsedTime()

    {       // 获得当前时间,返回当前时间和线程创建时间的差值

             DWORD dwElapsed = ::GetTickCount();

             dwElapsed = dwElapsed - (DWORD)::TlsGetValue(g_tlsUsedTime);

             return dwElapsed;

    }

    GetTickCount函数可以取得Windows从启动开始经过的时间,其返回值是以毫秒为单位的已启动的时间。

    一般情况下,为各线程分配TLS索引的工作要在主线程中完成,而分配的索引值应该保存在全局变量中,以方便各线程访问。上面的例子代码很清除地说明了这一点。主线程一开始就使用TlsAlloc为时间跟踪系统申请了一个索引,保存在全局变量g_tlsUsedTime中。之后,为了示例TLS机制的特点同时创建了10个线程。这10个线程最后都打印出了自己的生命周期,如图3.10所示。

     
    展开全文
  • 《Linux 中的线程局部存储(1)》提到了一种,其实在Linux中还有一种更为高效的线程局部存储方法,是使用关键字__thread来定义变量。  __thread是GCC内置的线程局部存储设施(Thread-Local Storage),它的实现...
  • 线程局部存储TLS

    2015-07-06 09:17:57
    windows线程局部存储TLS原理与解释
  • 主要介绍了C++采用TLS线程局部存储的用法实例,详细讲述了TLS索引及线程的操作,非常具有实用价值,需要的朋友可以参考下
  • 针对该情况,使用线程局部存储技术实现全局变量的局部化,采用具有大量全局变量的实体仿真代码实现ActiveX封装。该技术已成功应用于基于工业以太网的多通道数控系统中。  关键词:数控系统;线程局部存储;组件...
  • 关于线程局部存储,既然是为了保证各个线程有自己私有的全局变量和静态共享变量,那么它与线程同步机制(临界区、信号量、事件、互斥量)有什么关联呢? 望各路大侠参与讨论、指导!新申请的账号,没有积分,多海涵...
  • 7. 线程局部存储技术7.1. 简介我们知道,在一个进程中,所有线程的堆内存是共享的(栈除外,线程的栈内存是相互隔离的)。线程局部存储技术是使每个线程与其它线程数据存储隔离。 NET Framework 提供了两种用于使用...

    7. 线程局部存储技术

    7.1. 简介

    我们知道,在一个进程中,所有线程的堆内存是共享的(栈除外,线程的栈内存是相互隔离的)。线程局部存储技术是使每个线程与其它线程数据存储隔离。

     

    NET Framework 提供了两种用于使用线程本地存储区 (TLS) 机制︰ 线程相对静态字段 (即,使用标记的字段 ThreadStaticAttribute 属性) 和数据槽。 线程相关的静态字段提供更好的性能比数据槽,并启用了编译时类型检查。

    7.2. 线程相对静态字段

    以 ThreadStaticAttribute 特性标记的静态字段(注意:一定要是静态字段

    看这个例子:

     

    class ThreadData

    {

        [ThreadStaticAttribute]

        static intthreadSpecificData;

        public static voidThreadStaticDemo()

        {

            threadSpecificData =Thread.CurrentThread.ManagedThreadId;

    //设置休眠,使其它线程也执行休眠前的代码,

    //从而展示该静态字段针对每一个线程都是唯一的

            Thread.Sleep( 1000 );

            Console.WriteLine("Data for managed thread {0}: {1}",

                Thread.CurrentThread.ManagedThreadId,threadSpecificData );

        }

    }

    static void Main()

    {

        for(int i = 0; i < 3;i++)

        {

           Thread newThread = newThread(ThreadData.ThreadStaticDemo);

           newThread.Start();

        }

     }

     

    输出结果:

    Data for managed thread 4: 4

    Data for managed thread 5: 5

    Data for managed thread 3: 3

    从结果上可以看出,threadSpecificData这个静态字段对每一个线程都是唯一的。

     

    7.3. 数据槽

    Thread.GetData从一个线程的隔离数据中读,Thread.SetData写入数据。 两个方法需要一个LocalDataStoreSlot对象来识别数据槽,该数据槽需要一个名称,这个名称你可以跨所有的线程使用,它们将得到各自不同的值,看这个例子:

    class Slot

    {

        private staticRandom randomGenerator = new Random();

        public staticvoid SlotTest()

        {

            intslotData = randomGenerator.Next(1, 200);

            intthreadId = Thread.CurrentThread.ManagedThreadId;

           LocalDataStoreSlot  ls = Thread.GetNamedDataSlot("Random");

           Thread.SetData(ls, slotData);

            // Showwhat was saved in the thread's data slot.

           Console.WriteLine("Data stored in thread_{0}'s data slot:{1,3}",

                threadId, slotData);

    //设置休眠,使其它线程也执行休眠前的代码,

    //从而展示同名称的数据槽对每一个线程都是唯一的

           Thread.Sleep(1000);

            intnewSlotData =(int)Thread.GetData(Thread.GetNamedDataSlot("Random"));

            if(newSlotData == slotData)

            {

               Console.WriteLine("Data in thread_{0}'s data slot is still:{1,3}",

                   threadId, newSlotData);

            }

            else

            {

               Console.WriteLine("Data in thread_{0}'s data slot changed to:{1,3}",

                   threadId, newSlotData);

            }

        }

    }

     

    public static void Main()

    {

         Thread[]newThreads = new Thread[4];

         int i;

         for (i = 0; i< newThreads.Length; i++)

         {

            newThreads[i] =new Thread(new ThreadStart(Slot.SlotTest));

            newThreads[i].Start();

          }

    }


    展开全文
  • TLS(线程局部存储).zip

    2020-04-02 22:33:45
    《Windows PE权威指南》TLS学习代码 实现TLS表定位,枚举; 实现动态线程存储 实现静态线程存储 可与《PE文件:TLS线程局部存储》配套使用 https://blog.csdn.net/weixin_43742894/article/details/105235426
  • 线程局部存储机制的实现 稍微底层了一点点
  • 本文将从线程局部存储方面,简单讲解处理这一类线程安全问题的方法。  一、数据类型  在C/C++程序中常存在全局变量、函数内定义的静态变量以及局部变量,对于局部变量来说,其不存在线程安全问题,因此不在本文...
  • C++ 之线程局部存储

    2020-06-30 07:44:18
    线程局部存储(TLS,thread local storage)是一个已有的概念。简单地说,所谓线程局部存储变量,就是拥有线程生命期及线程可见性的变量。 线程局部存储实际上是由 单线程程序中的全局/静态变量被应用到多线程程序中...

     


    线程局部存储(TLS,thread local storage)是一个已有的概念。简单地说,所谓线程局部存储变量,就是拥有线程生命期及线程可见性的变量。

    线程局部存储实际上是由 单线程程序中的全局/静态变量被应用到多线程程序中 被线程共享而来。

    通常情况下,线程会拥有自己的栈空间,但是堆空间、静态数据区(如果从可执行文件的角度来看,静态数据区对应的是可执行文件的data、bss段的数据,而从C/C++语言层面而言,则对应的是全局/静态变量)则是共享的。这样一来,全局、静态变量在这种多线程模型下就总是在线程间共享的。

    全局、静态变量的共享虽然会带来一些好处,尤其对一些资源性的变量(比如文件句柄)来说也是应该的,不过并不是所有的全局、静态变量都适合在多线程的情况下共享。

    例如:代码清单6-27所示的例子:

    MaySetErr函数会根据输入值input设置全局的错误码errorCode。当用两个线程运行该函数的时候,最终获得的errorCode的值将是不确定的,或者说,将由系统如何调度两个线程而决定。

    实际上,本例中的errorCode即是POSIX标准中的全局变量错误码errno在多线程情况下遭遇的问题的一个简化。一旦errno在线程间共享,则一些程序中运行的错误将会被隐藏不报。而解决的办法就是为每个线程指派一个全局的errno,即TLS化的errno

    各个编译器公司都有自己的TLS标准。我们在g++/clang++/xlc++中可以看到如下的语法:

    __thread int errCode;

    即在全局或者静态变量的声明中加上关键字__thread,即可将变量声明为TLS变量。每个线程将拥有独立的errCode的拷贝,一个线程中对errCode的读写并不会影响另外一个线程中的errCode的数据

     

    C++11对TLS标准做出了一些统一的规定。与__thread修饰符类似,声明一个TLS变量的语法很简单,即通过thread_local修饰符声明变量即可。

    int thread_ local errCode;

     

    一旦声明一个变量为thread_local,其值将在线程开始时被初始化,而在线程结束时,该值也将不再有效。对于thread_local变量地址取值(&),也只可以获得当前线程中的TLS变量的地址值。


    虽然TLS变量的声明很简单,使用也很直观,不过实际上TLS的实现需要涉及编译器、链接器、加载器甚至是操作系统的相互配合。在TLS中一个常被讨论的问题就是TLS变量的静态/动态分配的问题,即TLS变量的内存究竟是在程序一开始就被分配还是在线程开始运行时被分配。通常情况下,前者比后者更易于实现。     C++11标准允许平台/编译器自行选择采用静态分配或动态分配,或者两者都支持。

     

    还有一点值得注意的是,C++11对TLS只是做了语法上的统一,而对其实现并没有做任何性能上的规定。这可能导致

    thread_local声明的变量在不同平台或者不同的TLS实现上出现不同的性能(通常TLS变量的读写性能不会高于普通的全局/静态变量)。如果读者想得到最佳的平台上的TLS变量的运行性能的话,最好还是阅读代码运行平台的相关文档。


    ---6.4chapter

    展开全文
  • 在一个进程中定义的全局或静态变量都是所有线程可见的,即每个线程共同操作一块存储区域。...线程局部存储和线程特有数据都可以实现上述需求。 1. 线程局部存储 线程局部存储提供了持久的每线程存储,每个线程都...
  • 线程局部存储实现

    千次阅读 2015-05-25 11:38:48
    《程序员的自我修养:链接、装载与库》第11章运行库。...本节为大家介绍线程局部存储实现。   11.3.3 线程局部存储实现(1) 很多时候,开发者在编写多线程程序的时候都希望存储一些线程私有的数据。我们知
  • Linux线程局部存储

    2014-11-29 22:49:25
    在Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同一变量的多线程读写问题,大多情况下遇到这类问题都是通过锁机制来处理,但这对程序的性能带来了很大的影响,当然...本文将从线程局部存储方面,简单
  • Windows 下实现线程局部存储

    千次阅读 2015-10-26 23:23:44
    以下叙述的仅是Windows NT,XP 等系统下实现线程局部存储的一个思路,并不是绝对的实现方法。 线程局部存储(Thread Local Storage,TLS),是多线程普及的情况下一个很有用的机制,该机制使得线程可以使用属于自己...
  • 针对该情况,使用线程局部存储技术实现全局变量的局部化,采用具有大量全局变量的实体仿真代码实现ActiveX封装。该技术已成功应用于基于工业以太网的多通道数控系统中。  关键词:数控系统;线程局部存储;组件...
  • ESP32 官方文档(十)线程局部存储

    千次阅读 2018-09-02 15:59:35
    线程局部存储 (TLS) 是一种机制,通过该机制分配变量,使每个现存线程有一个变量实例. ESP-IDF 提供了三种利用这些变量的方法: FreeRTOS 原生 API: ESP-IDF FreeRTOS 原生 API. 多线程 API:ESP-IDF 的多线程 API....
  • 线程局部存储(TLS)

    千次阅读 2013-04-10 10:57:06
    线程局部存储,Part 1:概述 线程局部存储,Part 2:显式TLS 线程局部存储,Part 3:编译器和链接器对隐式TLS的支持 线程局部存储,Part 4:访问__declspec(thread)变量 线程局部存储,Part 5:加载器对__...
  • 理解线程局部存储

    2018-10-14 23:54:01
    线程局部存储区,英文总称Thread local Storage,简TLS。 那TLS有什么用处呢?起始我们可以使用TLS将数据于一个正在运行的线程关联起来。将数据与线程关联起来是有帮助的,比如我们使用TLS来确定线程运行了多长时间...
  • 在Linux中还有一种更为高效的线程局部存储方法,就是使用关键字__thread来定义变量。__thread是GCC内置的线程局部存储设施(Thread-Local Storage),它的实现非常高效,与pthread_key_t向比较更为快速,其存储...
  • 有关TLS(线程局部存储)的题目或者源代码,已经学了一部分,深层次点的,谢谢
  • TLS--线程局部存储

    2013-05-27 11:17:28
    TLS--线程局部存储 概念:线程局部存储(Thread Local Storage,TLS)用来将数据与一个正在执行的指定线程关联起来。 进程中的全局变量与函数内定义的静态(static)变量,是各个线程都可以访问的共享变量。在一...
  • 线程局部存储在其它语言中都是以库的形式提供的(库函数或类)。但在C++11中以关键字的形式,做为一种存储类型出现,由此可见C++11对线程局部存储的重视。C++11中有如下几种存储类型: 序号 类型 备注 1 auto ...
  • TLS 线程局部存储

    2014-05-21 00:09:42
    TLS(Thread Local Storage) 线程局部存储  所有的线程都共享着进程的虚拟地址~ 局部变量为每个线程所独立共享的,静态变量和全局变量是进程中所有线程一起共享的~ TLS可以为线程提供一个唯一的数据用一个全局的...
  • 线程局部存储tls的使用

    千次阅读 2016-11-17 16:04:41
    线程局部存储(Thread Local Storage,TLS)主要用于在多线程中,存储和维护一些线程相关的数据,存储的数据会被关联到当前线程中去,并不需要锁来维护。。因此也没有多线程间资源竞争问题,那如何去实现TLS存储呢,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 155,449
精华内容 62,179
关键字:

线程局部存储