https://www.jianshu.com/p/495ea7ce649b?utm_source=oschina-app

该博客还未学习完  还有   pthread_key_t    Thread_local

__thread 修饰的变量

  • __thread是GCC内置的线程局部存储设施,__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是各线程独立不干扰的变量;
  • 只能修饰POD类型(类似整型指针的标量),不能修饰class类型,因为无法自动调用构造函数和析构函数;
  • 可以用于修饰全局变量,函数内的静态变量,不能修饰函数的局部变量或者class的普通成员变量;
  • 且__thread变量值只能初始化为编译器常量。
#include <pthread.h>
#include <cstdio>
#include <cstdlib>
#include <assert.h>
#include <stdint.h> __thread uint64_t pkey = ; void run2( )
{
FILE* fp = NULL;
cout<<"thread1 run2 thread = "<<pkey<<endl;//有值了 if( !pkey )
{
char fName[] = "";
sprintf( fName, "thread%lu.log", static_cast<unsigned long>( pthread_self() ) );
fp = fopen( fName, "w" );
pkey = reinterpret_cast<uint64_t>( fp ); }else fp = reinterpret_cast<FILE*>( pkey ); fprintf( fp, "hello __thread 2\n" );
return ;
} void* run1( void* arg )
{
FILE* fp = NULL;
cout<<"thread1 run1 thread = "<<pkey<<endl;// if( !pkey )
{
char fName[] = "";
sprintf( fName, "thread%lu.log", static_cast<unsigned long>( pthread_self() ) );
fp = fopen( fName, "w" );
pkey = reinterpret_cast<uint64_t>( fp ); }else fp = reinterpret_cast<FILE*>( pkey ); fprintf( fp, "hello __thread 1\n" ); run2(); return NULL;
} int main(int argc, char const *argv[])
{
char fName[] = "";
sprintf( fName, "thread%lu.log", static_cast<unsigned long>( pthread_self() ) );
FILE* fp = fopen( fName, "w" );
cout<<"main thread = "<<pkey<<endl;// pkey = reinterpret_cast<uint64_t>( fp );
fprintf( fp, "hello __thread\n" );
cout<<"main thread end = "<<pkey<<endl;///其他值 pthread_t threads[];
pthread_create( &threads[], NULL, run1, NULL );//开启线程
pthread_create( &threads[], NULL, run1, NULL );
pthread_join( threads[], NULL );
pthread_join( threads[], NULL );
return ;
} main thread =
main thread end =
thread1 run1 thread =
thread1 run2 thread =
thread1 run1 thread =
thread1 run2 thread = 一共创建了 3个文件 分别对应三个线程

pthread_key_t

pthread_key_t 优于 __thread 从下面几个方面来说:

  • 依赖 linux 环境的 libpthread, 而非 gcc 编译器可移植性增强
  • 如上所示,可以认为对每个 pthread_key, 库内部提供了一个 __thread void* 接受 pthread_setspecific 设置的指针,从而可以指向 class 类型
  • pthread_key_t 可以作为函数的局部变量,也可以作为局部变量
#include <pthread.h>
// pthread_key_t, pthread_setspecific, pthread_getspecific, pthread_self
// pthread_key_create, pthread_key_delete, pthread_create, pthread_join
#include <iostream>
#include <cstdio>
#include <cstdlib> using namespace std; static pthread_key_t pkt;
// 1, callback function to destroy resource associated with key
// 2, the in_param is pthread_getspecific()
// 3, gettid()是内核给线程(轻量级进程)分配的进程id,全局(所有进程中)唯一
// 4, pthread_self()是在用户态实现的,获取的id实际上是主线程分配给子线程的线程描述符的地址而已,只是在当前进程空间中是唯一的。
void destroy( void *arg )
{
printf("exit at thread %d, fclose file \n", static_cast<int>( pthread_self() ) );
if( arg ) fclose( reinterpret_cast<FILE*>(arg) );
}
// 5, pthread_getspecific() Return current value of the thread-specific data slot identified by KEY.
void writeLog( const char* log )
{
FILE* logHandle = reinterpret_cast<FILE*>( pthread_getspecific( pkt) );
fprintf( logHandle, "%s\n", log );
}
// 6, pthread_setspecific Store POINTER in the thread-specific data slot identified by KEY
void* work( void* arg)
{
FILE* logHandle = NULL;
char fileName[128] = "";
sprintf( fileName, "Thread%d.log", static_cast<int>(pthread_self()) );
logHandle = fopen( fileName, "w");
pthread_setspecific( pkt, reinterpret_cast<void*>( logHandle ) );
writeLog( "Thread starting." );
}
// 7, pthread_key_create( &pkt, destroy ) Create a key value identifying a location in the thread-specific      //identifying 识别
// data area. Each thread maintains a distinct thread-specific data area.
// the destroy callback function will called with the key is dectroyed
// 8, pthread_key_delete( ) detroy the key use callback function clear the resource
int main(int argc, char const *argv[])
{
pthread_key_create( &pkt, destroy );
pthread_t pids[2] = {0};
pthread_create( &pids[0], NULL, work, NULL );
pthread_create( &pids[1], NULL, work, NULL );
pthread_join( pids[0], NULL );
pthread_join( pids[1], NULL );
pthread_key_delete( pkt );
printf("stop\n");
return 0;
}

  

ThreadLocal

对 pthread_key_t 进行了 RAII 的封装,使用更加安全。

#include <pthread.h>
#include <boost/noncopyable.hpp> // noncopyable
#include <boost/checked_delete.hpp> // check_delete
#include <cstdio>
#include <cstdlib>
#include <string>
#include <stdexcept> template<typename T>
class ThreadLocal : public boost::noncopyable
{
public:
typedef ThreadLocal<T>* pThreadLocal;
ThreadLocal()
{ pthread_key_create( &pkey_, &ThreadLocal::destroy ); } ~ThreadLocal()
{ pthread_key_delete( pkey_ ); } T& value()
{
T* pvalue = reinterpret_cast<T*>( pthread_getspecific( pkey_ ) );
if( !pvalue )
{
T* obj = new T();
pthread_setspecific( pkey_, reinterpret_cast<void*>( obj ) );
pvalue = obj;
}
return *pvalue;
} private:
static void destroy( void* arg )
{
T* obj = reinterpret_cast<T*>( arg );
boost::checked_delete( obj );
} pthread_key_t pkey_;
}; class Logger
{
public:
Logger()
{
char fName[128] = "";
sprintf( fName, "log_%lu.log", static_cast<unsigned long>( pthread_self() ) );
fp = fopen( fName, "w" );
if( !fp ) throw std::runtime_error( std::string("can not create ") + fName );
} ~Logger() { fclose( fp ); } void log( const std::string& s ) { fprintf( fp, "%s\n", s.c_str() ); } private:
FILE* fp;
}; void* run( void* arg )
{
auto ptllogger = reinterpret_cast< ThreadLocal<Logger>::pThreadLocal>( arg);
Logger& plogger = ptllogger->value();
plogger.log( "Hello thread local" );
} int main()
{
ThreadLocal<Logger>::pThreadLocal p = new ThreadLocal<Logger>;
Logger& plogger = p->value();
plogger.log( "Hello thread local" ); pthread_t threads[2] = {0};
pthread_create( &threads[0], NULL, run, reinterpret_cast<void*>( p ) );
pthread_create( &threads[1], NULL, run, reinterpret_cast<void*>( p ) );
pthread_join( threads[0], NULL );
pthread_join( threads[1], NULL );
delete p;
}

  需要 打开原始连接 看看

线程局部存储空间 pthread_key_t、__thread 即 ThreadLocal的更多相关文章

  1. 并发基础(十) 线程局部副本ThreadLocal之正解

      本文将介绍ThreadLocal的用法,并且指出大部分人对ThreadLocal 的误区. 先来看一下ThreadLocal的API: 1.构造方法摘要 ThreadLocal(): 创建一个线程 ...

  2. RocksDB线程局部缓存

    概述 在开发过程中,我们经常会遇到并发问题,解决并发问题通常的方法是加锁保护,比如常用的spinlock,mutex或者rwlock,当然也可以采用无锁编程,对实现要求就比较高了.对于任何一个共享变量 ...

  3. 线程封闭之栈封闭和ThreadLocal

    线程封闭 在多线程的环境中,我们经常使用锁来保证线程的安全,但是对于每个线程都要用的资源使用锁的话那么程序执行的效率就会受到影响,这个时候可以把这些资源变成线程封闭的形式. 1.栈封闭 所谓的栈封闭其 ...

  4. Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

    Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离.

  5. 4、线程范围内的数据共享之ThreadLocal

    /** * 线程范围类的数据共享 * 核心:ThreadLocal类 * 实际场景: * Hibernate的getCurrentSession方法,就是从线程范围内获取存在的session,如果不存 ...

  6. Java线程和多线程(七)——ThreadLocal

    Java中的ThreadLocal是用来创建线程本地变量用的.我们都知道,访问某个对象的所有线程都是能够共享对象的状态的,所以这个对象状态就不是线程安全的.开发者可以通过使用同步来保证线程安全,但是如 ...

  7. 线程范围内的环境变量---ThreadLocal

    package cn.itcast.heima2; import java.util.HashMap; import java.util.Map; import java.util.Random; p ...

  8. 过虑器 ThreadLocal 权限 监听器 观察者模式

    数据的压缩 GzipOutputStream - > > ByteArrayOutputStream. 以下是在某个servlet中对指定的数据进行压缩 package cn.itcast ...

  9. 用ThreadLocal管理事务

    1.适用场景 一个service,操作两个dao,要求两个dao为同一个事务,要么全成功,要么全失败.

随机推荐

  1. python操作mysql数据库系列-安装MySQLdb

    一波三折,先是pip命令出现问题,然后各种方法尝试解决.然后是直接使用pip2命令安装报错,mysql-python库安装再次出现问题.于是使用国内镜像的方式去安装:pip2 install MySQ ...

  2. Nginx根据用户请求的不同参数返回不同的json值

    用户请求url:http://localhost:8000/getconfig?v=1.03.01,根据参数v=1.03.01或者其他的值返回不同的json值.如果用户请求不带该参数,则返回默认的js ...

  3. Maven整理笔记の生命周期和插件

    项目构建的生命周期,其实软件开发人员每天都在干这个事,即项目清理.初始化.编译.测试.打包.集成测试.验证.部署和站点生成等,可以说几乎所有项目的构建都可以映射到这样一个生命周期上. Maven的插件 ...

  4. GetFileVersionInfoSize函数确定操作系统是否可以检索指定文件的版本信息

    GetFileVersionInfoSize函数 -------------------------------------------------- ------------------------ ...

  5. C++ 的写好库编译好,DELPHI或者Java做界面,iOS 和 Android 就都搞定。

    当然也可以使用BCB和相关的开发库来开发App,只是别人没法帮助你. 摘自<想到做到-Android开发关键技术与精彩案例>.(詹建飞) p40

  6. Java == 和 equals 比较

    在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str2 = new String(&qu ...

  7. simrank

    simrank 背景 度量相似度是许多应用的关键问题.传统方法与问题的领域相关,如文本匹配.计算交集.simrank则利用关联关系度量相似性,即"两个节点的相似性和各自邻域节点的相似度有关& ...

  8. TSQL--可以在触发器中使用COMMIT吗?

    很多场景中,我们使用触发器来回滚一些不满足业务逻辑的修改,这没有问题,问题是我能在触发器中提交事务吗? 这个问题很小白,当也来测试一下 /*测试中创建三种表,对表 TB2 插入时触发触发器,在触发器中 ...

  9. Nutch2.x 集成ElasticSearch 抓取+索引

    http://blog.csdn.net/eryk86/article/details/14111811   使用https://github.com/apache/nutch.git导入nutch项 ...

  10. django drf GenericAPIView和ListAPIView

    drf提供了更快捷的查询方法ListModelMixin+GenericAPIView,和ListAPIView 1.ListModelMixin+GenericAPIView from django ...