线程本地存储(TLS)的学习

来源:互联网 发布:windows怎么开ssh 编辑:程序博客网 时间:2024/06/05 14:38

@原创文章,转载请注明: 转载自 镜中影的技术博客 
本文链接地址: 线程本地存储(TLS)的学习) 
URL:http://blog.csdn.net/linkpark1904/article/details/50790998

一、引言

最近在看jemalloc的文章 A Scalable Concurrent malloc(3) Implementation for FreeBSD, 文中有提到,在分配Arena的时候用到了线程本地存储技术(thread-local storage),这里发散一下,复习一下什么是线程本地存储。

二、简介

Thread-local storage,也就是在多线程程序中,为每个线程提供该线程独占的静态或者全局内存区域。说白了,也就是每个线程独享的全局变量。重所周知,在一个进程中,全局区的数据是被该进程的所有线程所共享的,而全局变量和静态变量位于内存地址空间中的全局数据区。然而,线程作为一个独立的执行体,能否有自己独有的全局变量呢?于是,就有了TLS技术。

三、示例

Windows下和Linux下对于线程本地存储的实现技术不同,所提供的接口也不一样。没关系,这里示例学习中,采用C++11。c++11将线程进行了封装,线程类位于<thread>中,示例代码如下:

#include <iostream>#include <thread>#include <unistd.h>#include <mutex>using namespace std;int var(0);//thread_local int var(0);std::mutex mtx;void StartFunc() {    std::unique_lock<std::mutex> lck (mtx);    var++;    cout << "Thread id:" <<  std::this_thread::get_id()        << " var:" <<var << endl; }int main() {    for( int i = 0; i < 4; ++i ) {        std::thread( StartFunc ).detach();    }    ::sleep(3);   }
  • 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
  • 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

其中Thread对象就是C++11中已经封装好的线程类对象,接收一个函数名作为参数,创建一个线程,这里创建四个线程,分别对全局变量var 进行操作,结果可想而知:

执行结果

每个线程共享var变量,所以var变量是累加的。那么换成TSL变量呢?在c++11中,TSL变量很简单,C++11提供关键字thread_local,对于全局变量的生命,改成thread_local int var(0); 执行结果变为: 
这里写图片描述

因为这个变量被每个线程独享,所以变量的值不会共享给其他的线程。

四、应用场景

那么问题来了,为什么会有TLS呢,举一个应用场景,对于errno的操作,如果errno是全局共享的,那么一个线程中错误码被设置了,那么很可能,这个错误码会被后面的一个线程给覆盖,这样,就没法拿到前一个线程的错误码了,所以,对于错误码errno,最好的方式是提供TLS,让每个线程都拥有自己的错误码,线程之间互不影响,一旦线程执行出错,就可以拿到这个线程的错误原因了。