线程id
Linux中,每个进程有一个pid,类型pid_t,由getpid()取得。
Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。
有时候我们可能需要知道线程的真实pid。比如进程P1要向另外一个进程P2中的某个线程发送信号时,既不能使用P2的pid,更不能使用线程的pthread id,而只能使用该线程的真实pid,称为tid。有一个函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过Linux的系统调用syscall来获取。
return syscall(SYS_gettid)
线程私有数据
1.__thread : gcc内置的线程局部存储设施
__thread只能修饰POD类型POD类型(plain old data),与C兼容的原始数据,例如,结构和整型等C语言中的类型是 POD 类型,但带有用户定义的构造函数或虚函数的类则不是
__thread string t_obj1(“cppcourse”); // 错误,不能调用对象的构造函数
__thread string* t_obj2 = new string; // 错误,初始化只能是编译期常量
__thread string* t_obj3 = NULL; // 正确
2.Posix线程私有数据
(Thread-specific Date)TSD
实现原理:http://blog.csdn.net/le119126/article/details/45025297。 http://blog.csdn.net/caigen1988/article/details/7901248、http://blog.csdn.net/hudashi/article/details/7709430
相当于二级索引,key数组(一级索引)整个进程共享,标志哪些key使用与否,每个线程有自己pkey数组(二级索引),存在pthread结构中,pkey数组存储自己私有数据的指针。key --》pkey- -》私有数据指针
pthread_key_create(创建一个键),pthread_setspecific(为一个键设置线程私有数据),pthread_getspecific(从一个键读取线程私有数据),pthread_key_delete(删除一个键)。这几个函数的声明如下:
#include <pthread.h>
int pthread_key_create(pthread_key_t *key,void (*destr_function)(void *));
int pthread_setspecific(pthread_key_t key,const void *pointer));
void *pthread_getspecific(pthread_key_t key);
int pthread_key_delete(pthread_key_t key);
#include <pthread.h>
int pthread_key_create(pthread_key_t *key,void (*destr_function)(void *));
int pthread_setspecific(pthread_key_t key,const void *pointer));
void *pthread_getspecific(pthread_key_t key);
int pthread_key_delete(pthread_key_t key);
boost :: is_same
类型是否一样
存储类:
存储类可分为auto、register、static、extern、mutable、thread_local(__thread)等
mutable
mutable存储类只能用于类的数据成员,不能用于普通变量。具有mutable性质的类的数据成员打破了类对象的const限定,允许修改类的mutable的数据成员,即便类的其它成员仍然是const只读属性。
thread_local
适用于命名空间内的变量、全局作用域的变量、函数内部定义的静态变量,如果使用了thread_local关键字,则在
运行时不同的线程具有该变量的不同的存储位置,即各有各的副本。因此,具有thread_local存储类的变量,必然具有static存储类性质,不管是否使用了static关键字。
class CurrenThread{ public: static __thread int a; }; __thread int test::a=0;
源码分析
detail命名空间:一些公共、初始化操作,其中有调用CurrentThread::tid( )
CurrentThread::tid() 在CurrentThread 命名空间,也有调用detail的detail::gettid( )
他们有相互调用
CurrentThread命名空间:本线程基本信息,没有封装成类(类用__thread麻烦),直接裸露在命名空间里,都是__thread 私有数据
ThreadNameInitalizer init;//全局变量,在main函数开始前就构造,完成启动初始化配置(pthread_atfork),且就一次,这一次就标示了 主线程的名字CurrenThread::t_ThreadName="main"
//Thread.h #ifndef MUDUO_BASE_THREAD_H #define MUDUO_BASE_THREAD_H #include <muduo/base/Atomic.h> #include <muduo/base/Types.h> #include <boost/function.hpp> #include <boost/noncopyable.hpp> #include <pthread.h> namespace muduo { class Thread : boost::noncopyable { public: typedef boost::function<void ()> ThreadFunc; explicit Thread(const ThreadFunc&,const string& name=string()); ~Thread(); void start(); int join();// return pthread_join bool started() const {return started_;} pthread_t pthreadId() const {return pthreadId_;} pid_t tid() const {return tid_;} static int numCreated() {return numCreated_.get();} private: static void* startThread(void* thread); void runInThread(); bool started_; pthread_t pthreadId_; pid_t tid_; ThreadFunc func_; string name_; static AtomicInt32 numCreated_; }; } #endif
//CurrentThread.h namespace muduo { namespace CurrentThread { //internal extern __thread int t_cachedTid; extern __thread char t_tidString[32]; extern __thread const char* t_threadName; void cacheTid(); inline int tid() { if(t_cachedTid==0) cacheTid(); return t_cachedTid; } inline const char* tidString() { return t_tidString; } inline const char* name() { return t_threadName; } bool isMainThread(); } } #endif
//Thread.cc #include <muduo/base/Thread.h> #include <muduo/base/CurrentThread.h> #include <muduo/base/Exception.h> //#include <muduo/base/Logging.h> #include <boost/static_assert.hpp> #include <boost/type_traits/is_same.hpp> #include <errno.h> #include <stdio.h> #include <unistd.h> #include <sys/syscall.h> #include <sys/types.h> #include <linux/unistd.h> namespace muduo { /* class CurrenThread{ public: static __thread int a; }; __thread int test::a=0; */ //CurrentThread 线程信息,如果组织成类就得像上面那样麻烦,所以直接裸露在命名空间里,全是私有全局变量 namespace CurrentThread { __thread int t_cachedTid = 0;//真实pid __thread char t_tidString[32]; __thread const char* t_threadName = "unknown";//其实只有main,started,finished,crashed这四个名字( 在Thread::runInThread()中对其修改 ),用来表示线程状态的而已,线程真正名字时Thread::name_ const bool sameType = boost::is_same<int, pid_t>::value; BOOST_STATIC_ASSERT(sameType); } //一些公共初始化操作 namespace detail { pid_t gettid() { return static_cast<pid_t>(::syscall(SYS_gettid)); } //设置fork后的主线程状态,不需要显示调用,下面用全局变量ThreadNameInitalizer的构造函数调用了 void afterFork() { muduo::CurrentThread::t_cachedTid=0; muduo::CurrentThread::t_threadName="main"; CurrentThread::tid();//如果t_cachedTid等于0,就先调用cachedTid(),在返回t_cachedTide.其实这句就是为了缓存t_cachedTid( detail 中调用 CurrentThread) } class ThreadNameInitalizer { public: ThreadNameInitalizer() { muduo::CurrentThread::t_threadName = "main"; CurrentThread::tid(); pthread_atfork(NULL,NULL,&afterFork); } }; ThreadNameInitalizer init;//全局变量,在main函数开始前就初始化,且就一次,这一次就标示了main 主线程 } using namespace muduo; void CurrentThread::cacheTid() { if(t_cachedTid == 0) { t_cachedTid = detail::gettid();//CurrentThread 调用 detail int n = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid); assert(n == 6); (void) n; } } bool CurrentThread::isMainThread() { return tid() == ::getpid(); } AtomicInt32 Thread ::numCreated_;//因为numCreated_是静态的,一定要定义,不能只在头文件中声明 Thread::Thread(const ThreadFunc& func, const string& n) :started_(false), pthreadId_(0), tid_(0), func_(func), name_(n) { numCreated_.increment(); } Thread::~Thread() {} void Thread::start() { assert(!started_); started_=true; errno = pthread_create(&pthreadId_, NULL, &startThread, this); if(errno != 0) { //LOG_SYSFATAL << "Failed in pthread_create"; } } int Thread::join() { assert(started_); return pthread_join(pthreadId_,NULL); } void* Thread::startThread(void* obj) { Thread* thread=static_cast<Thread*>(obj); thread->runInThread(); return NULL; } void Thread::runInThread() { tid_=CurrentThread::tid(); muduo::CurrentThread::t_threadName=name_.c_str(); try { func_(); muduo::CurrentThread::t_threadName="finished"; } catch(const Exception& ex) { muduo::CurrentThread::t_threadName="crashed"; fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); fprintf(stderr, "reason: %s\n", ex.what()); fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); abort(); } catch (const std::exception& ex) { muduo::CurrentThread::t_threadName = "crashed"; fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); fprintf(stderr, "reason: %s\n", ex.what()); abort(); } catch (...) { muduo::CurrentThread::t_threadName = "crashed"; fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str()); throw; // rethrow } } }相关: 线程属性与线程局部存储
参考:c++教程网