接下来,聊一聊主题–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();
}
#endif
Thread::~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.