首页 > 学院 > 开发设计 > 正文

浅析muduo库中的线程设施02

2019-11-08 02:33:16
字体:
来源:转载
供稿:网友

接下来,聊一聊主题–Thread

/***Thread.h***/class Thread : boost::noncopyable //禁止拷贝{ public: typedef boost::function<void ()> ThreadFunc;//仿函数对象,利用回调的方式使用线程函数 explicit Thread(const ThreadFunc&, const string& name = string());//普通的线程构造函数#ifdef __GXX_EXPERIMENTAL_CXX0X__ explicit Thread(ThreadFunc&&, const string& name = string());//移动的线程构造函数,比上面的更节省资源std::move#endif ~Thread();//析构函数 void start();//启动线程 int join(); // 类似于 pthread_join() bool started() const { return started_; } // pthread_t pthreadId() const { return pthreadId_; } pid_t tid() const { return *tid_; } //返回线程索引 const string& name() const { return name_; }//返回线程名字 static int numCreated() { return numCreated_.get(); } PRivate: void setDefaultName(); bool started_; //是否启动 bool joined_; //是否终止 pthread_t pthreadId_; //线程索引 boost::shared_ptr<pid_t> tid_; //指向线程索引的智能指针 ThreadFunc func_; //线程主题函数 string name_; //线程名字 static AtomicInt32 numCreated_; //static变量在所有的线程对象中共享,为由该类产生的线程排序};在muduo的线程对象封装中,最精彩的是使用boost::function函数对象将线程函数以回调的方式传递进线程对象中。

typedef boost::function<void ()> ThreadFun;

在多线程情况下,避免在对象外操作指向对象的指针的情形,可以在一定程度上保证了线程安全。/***Thread.cc***///两种线程构造函数Thread::Thread(const ThreadFunc& func, const string& n) : started_(false), joined_(false), pthreadId_(0), tid_(new pid_t(0)), func_(func), name_(n){ setDefaultName();}#ifdef __GXX_EXPERIMENTAL_CXX0X__Thread::Thread(ThreadFunc&& func, const string& n) : started_(false), joined_(false), pthreadId_(0), tid_(new pid_t(0)), func_(std::move(func)), name_(n){ setDefaultName(); }#endifThread::~Thread() { if (started_ && !joined_) //将该线程设置为分离属性 { pthread_detach(pthreadId_); //线程结束将自动回收资源 }}void Thread::setDefaultName() //设置线程名字,比如Thread1,Thread2等{ int num = numCreated_.incrementAndGet(); if (name_.empty()) { char buf[32]; snprintf(buf, sizeof buf, "Thread%d", num); name_ = buf; }}void Thread::start(){ assert(!started_); //断言线程是否已经开始运行 started_ = true; //断言失败则设置线程开始运行的标志 // FIXME: move(func_) detail::ThreadData* data = new detail::ThreadData(func_, name_, tid_); //获得线程运行的所需要的参数 if (pthread_create(&pthreadId_, NULL, &detail::startThread, data)) { //开始线程 started_ = false; printf("blockDim.x: %d/n",blockDim.x); delete data; // or no delete? LOG_SYSFATAL << "Failed in pthread_create"; }}int Thread::join(){ assert(started_); //断言线程是否正在运行 assert(!joined_); //断言线程是否已经被终止 joined_ = true; return pthread_join(pthreadId_, NULL); //等待线程结束}在线程的析构函数中只设置线程的分离属性,即等待线程运行结束后自动回收线程资源,不强行终止线程。struct ThreadData //thread的再封装{ typedef muduo::Thread::ThreadFunc ThreadFunc; ThreadFunc func_; string name_; boost::weak_ptr<pid_t> wkTid_; ThreadData(const ThreadFunc& func, const string& name, const boost::shared_ptr<pid_t>& tid) : func_(func), name_(name), wkTid_(tid) { } void runInThread()//真正让线程跑起来的函数 { pid_t tid = muduo::CurrentThread::tid(); boost::shared_ptr<pid_t> ptid = wkTid_.lock(); if (ptid) { *ptid = tid; ptid.reset(); } muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str(); ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName); 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 } }};void* startThread(void* obj) //由pthread_create调用的函数{ ThreadData* data = static_cast<ThreadData*>(obj); data->runInThread(); delete data; return NULL;}

将线程中的若干数据保存到ThreadData中,然后将ThreadData作为传递给pthread_create(...,void* arg)中的最后一个数据参数传递给void Thread(void* )标准的线程启动函数。然后在标准的线程启动函数内将void* arg强行转化为ThreadData,然后使用ThreadData中的runInThread函数启动线程。

在使用muduo的线程接口时,使用bind将线程运行函数再打包,然后传递进Thread.


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表