从零开始构建一个Reactor模式的网络库(二)线程类Thread
线程类Thread是对POSIX线程的封装类,因为要构建的是一个Linux环境下的多线程网络库,对线程的封装是很必要的。
首先是CurrentThread命名空间,主要是获取以及缓存线程id:
1 #ifndef CURRENTTHREAD_H 2 #define CURRENTTHREAD_H 3 #include <unistd.h> 4 #include <sys/syscall.h> 5 6 namespace CurrentThread 7 { 8 extern __thread int t_cachedTid; 9 inline void cacheTid() 10 { 11 t_cachedTid=static_cast<int>(::syscall(SYS_gettid)); 12 } 13 inline int tid() 14 { 15 if(t_cachedTid==0) 16 cacheTid(); 17 return t_cachedTid; 18 } 19 } 20 21 #endif // CURRENTTHREAD_H
这里要注意一个问题,就是线程id的获取。
线程id的获取可以通过几种方式,最方便的是syscall(),是一个glibc库函数而不是一个系统调用,此时返回的是内核中的线程id。
因为Linux的线程实现中,线程事实上也是一个进程,因此返回的tid事实上就是pid,pid_t在Linux中一般实现为int。
另外,POSIX线程库提供了函数pthread_self(),但是该函数返回的是进程中的线程id,类型为pthread_t,一般是unsigned long类型,并不是内核中的实际id,在调试和排查错误时并不方便。
1 #ifndef THREAD_H 2 #define THREAD_H 3 #include <pthread.h> 4 #include <memory> 5 #include <functional> 6 #include "Types.h" 7 #include <atomic> 8 #include "Mutex.h" 9 10 namespace mini 11 { 12 class Thread 13 { 14 public: 15 typedef std::function<void()> ThreadFunc; 16 explicit Thread(const ThreadFunc& func,const string& ThreadName=string()); 17 ~Thread(); 18 19 int join(); 20 void start(); 21 pid_t tid() const { return *tid_; } 22 bool started() const { return started_; } 23 const string& name() const {return name_;} 24 private: 25 26 void setDefaultName(); 27 28 bool started_; //if the thread started 29 bool joined_; //if joined settled 30 pthread_t pthreadId_; //thread id in the process 31 std::shared_ptr<pid_t> tid_; //shared_ptr to the tid 32 string name_; //name of the thread 33 ThreadFunc func_; //function for the thread 34 static std::atomic<int> numsCreated_; //record nums of created threads 35 }; 36 37 } 38 39 #endif // THREAD_H
Thread.h头文件中定义了Thread类,成员包括启动状态、tid和pthreadid、实际执行的函数以及名字等。
1 #include "CurrentThread.h" 2 #include "Thread.h" 3 #include <stdio.h> 4 #include <unistd.h> 5 #include <sys/syscall.h> 6 #include <sys/types.h> 7 8 namespace CurrentThread 9 { 10 __thread int t_cachedTid=0; 11 /* 12 bool isMainThread() 13 { 14 return ::getpid()==tid(); 15 } 16 */ 17 } 18 namespace mini 19 { 20 struct ThreadData 21 { 22 typedef mini::Thread::ThreadFunc ThreadFunc; 23 ThreadFunc func_; 24 mini::string name_; 25 std::weak_ptr<pid_t> wkTid_; 26 ThreadData(const ThreadFunc& func,const string& name,const std::shared_ptr<pid_t>& tid) 27 :func_(func),name_(name),wkTid_(tid) 28 {} 29 void runInThread() 30 { 31 pid_t tid=CurrentThread::tid(); 32 std::shared_ptr<pid_t> ptid=wkTid_.lock(); 33 if(ptid) 34 { 35 *ptid=tid; 36 ptid.reset(); 37 } 38 func_(); 39 } 40 41 }; 42 std::atomic<int> Thread::numsCreated_(0); 43 44 void Thread::setDefaultName() 45 { 46 int num=numsCreated_++; 47 if(name_.empty()) 48 { 49 char buf[32]; 50 snprintf(buf,sizeof buf,"Thread%d", num); 51 name_=buf; 52 } 53 } 54 55 void* startThread(void* obj) 56 { 57 ThreadData* data=static_cast<ThreadData*>(obj); 58 data->runInThread(); 59 delete data; 60 return NULL; 61 } 62 63 Thread::Thread(const ThreadFunc &func, const string &ThreadName) 64 :started_(false), 65 joined_(false), 66 pthreadId_(0), 67 tid_(new pid_t(0)), 68 func_(func), 69 name_(ThreadName) 70 { 71 setDefaultName(); 72 } 73 74 void Thread::start() 75 { 76 started_=true; 77 ThreadData* data=new ThreadData(func_,name_,tid_); 78 if(pthread_create(&pthreadId_,NULL,&startThread,data)); 79 { 80 started_=false; 81 //delete data; 82 //LOG_SYSFATAL<<"FAILED in pthread_create"; 83 } 84 } 85 86 int Thread::join() 87 { 88 joined_=true; 89 return pthread_join(pthreadId_,NULL); 90 } 91 92 Thread::~Thread() 93 { 94 if(started_&&!joined_) 95 pthread_detach(pthreadId_); 96 } 97 }
由于向pthread_create中传递要执行的线程函数以及参数比较复杂,定义了一个内部类ThreadData。
ThreadData中有一个weak_ptr<pid_t>,当线程实际被创建并开始运行时,创建一个临时的shared_ptr,确保Thread以及ThreadData被正确创建。
事实上,Thread类对象创建时,线程并没有实际开始运行,直到调用start()才开始执行。
执行线程可以调用join()来等待Thread线程的结束。默认情况下,线程资源会保留直到调用pthread_join()。
析构函数简单地调用pthread_detach()来设置线程分离,从而在线程函数执行结束后直接退出,线程资源也会在线程终止时立即被回收。