从零开始构建一个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()来设置线程分离,从而在线程函数执行结束后直接退出,线程资源也会在线程终止时立即被回收

 

posted @ 2018-12-18 11:22  luStar  阅读(464)  评论(0编辑  收藏  举报