来源 https://www.jianshu.com/p/495ea7ce649bhtml
参考: 线程局部变量 __thread 关键字linux
- __thread是GCC内置的线程局部存储设施,__thread变量每个线程有一份独立实体,各个线程的值互不干扰。能够用来修饰那些带有全局性且值可能变,可是各线程独立不干扰的变量;
- 只能修饰POD类型(相似整型指针的标量),不能修饰class类型,由于没法自动调用构造函数和析构函数;
- 能够用于修饰全局变量,函数内的静态变量,不能修饰函数的局部变量或者class的普通成员变量;
- 且__thread变量值只能初始化为编译器常量。
#include <pthread.h> #include <cstdio> #include <cstdlib> #include <assert.h> #include <stdint.h> __thread uint64_t pkey = 0; void run2( ) { FILE* fp = NULL; if( !pkey ) { char fName[128] = ""; 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; if( !pkey ) { char fName[128] = ""; 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[128] = ""; sprintf( fName, "thread%lu.log", static_cast<unsigned long>( pthread_self() ) ); FILE* fp = fopen( fName, "w" ); pkey = reinterpret_cast<uint64_t>( fp ); fprintf( fp, "hello __thread\n" ); pthread_t threads[2]; pthread_create( &threads[0], NULL, run1, NULL ); pthread_create( &threads[1], NULL, run1, NULL ); pthread_join( threads[0], NULL ); pthread_join( threads[1], NULL ); return 0; }
参考:关键字:__thread & pthread_key_tios
pthread_key_t 优于 __thread 从下面几个方面来讲:c++
- 依赖 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; }
参考:关键字:__thread & pthread_key_t安全
对 pthread_key_t 进行了 RAII 的封装,使用更加安全。app
#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; }
参见:深刻探索C++对象模型之指向成员函数的指针ide
class A { public: static void staticmember(){cout<<"static"<<endl;} //static member void nonstatic(){cout<<"nonstatic"<<endl;} //nonstatic member virtual void virtualmember(){cout<<"virtual"<<endl;};//virtual member }; int main() { A a; //static成员函数,取得的是该函数在内存中的实际地址,并且由于static成员是全局的,因此不能用A::限定符 void (*ptrstatic)() = &A::staticmember; //nonstatic成员函数 取得的是该函数在内存中的实际地址 void (A::*ptrnonstatic)() = &A::nonstatic; //虚函数取得的是虚函数表中的偏移值,这样能够保证能过指针调用时一样的多态效果 void (A::*ptrvirtual)() = &A::virtualmember; //函数指针的使用方式 ptrstatic(); (a.*ptrnonstatic)(); (a.*ptrvirtual)(); }
参见:c++ 数据类型转换: static_cast dynamic_cast reinterpret_cast const_cast函数
- 上行转换(把子类的指针或引用转换成基类表示), 下行转换(把基类指针或引用转换成子类表示)
- 类指针或引用的上行转换static_cast 和 dynamic_cast 均可以
- 类指针或引用的下行转换用dynamic_cast而且判断转换后是否为空
- 基本数据类型之间的转换用static_cast, 可是因为数值范围的不一样,须要用户保证转换的安全性
- 不一样类型之间的指针或引用的转换用reinterpret_cast,它的本质是对指向内存的比特位的重解释
- 消除数据的const、volatile、__unaligned属性,用const_cast
================ Endui