线程原生库的简单封装(二)
下面实现了一个通用的线程封装类Thread<T>
提供start()(创建线程)、join()(等待线程结束)、detach()(分离线程)、stop()(标记线程停止状态)等接口,覆盖了线程的基本操作需求。
#ifndef __THREAD_HPP__
#define __THREAD_HPP__#include <pthread.h>
#include <iostream>
#include <string>
#include <functional>
namespace ThreadModule
{template<typename T>using func_t = std::function<void(T)>;//将 std::function<void()> 这个类型起一个别名 func_t, 用于保存传入T参数,返回值为void的函数(可调用对象)template<typename T>class Thread{private:void Excute(){_func(_data);return;}public:Thread(func_t<T> func, T data, const std::string &name="none-name"): _func(func), _data(data), _threadname(name), _stop(true){}// static void *threadroutine(void* args)//类成员函数,形参是有this指针的,所以在前面要加static// {// _func(_data);// return nullptr;// }static void *threadroutine(void* args)//类成员函数,形参是有this指针的,所以在前面要加static{Thread<T> *self = static_cast<Thread<T>*>(args);self->Excute();return nullptr;}std::string name() const{return _threadname;}bool start(){int n = pthread_create(&_tid, nullptr, threadroutine, this);if(n != 0)//创建线程失败{return false;}else//创建线程成功{_stop = false;return true;}}void detach(){if(!_stop){pthread_detach(_tid);}}void join(){if(!_stop){pthread_join(_tid, nullptr);}}void stop(){_stop = true;}~Thread(){}private:pthread_t _tid;std::string _threadname;T _data;func_t<T> _func;bool _stop;};
}#endif // __THREAD_HPP__
细节一:
原生线程被使用时,类内成员函数被使用时,要加static,去掉this指针。
因为调用pthread_creare时传入的函数有格式要求只能是形如void *function(void* args)
,返回值必须是void类型,传入参数只有一个,是void类型。
但是在类中,作为成员函数,这个void *threadroutine(void* args)
函数的第一个参数实际上是this指针(Thread* const this
),用来传递自己属于哪个对象的。
所以这里要加上static,变成一个类的专属,这时没有this指针,符合pthread_creare时传入的函数的格式要求。
细节二:
static void *threadroutine(void* args)
{_func(_data);//这个函数无法直接用_datareturn nullptr;
}
这里是行不通的,加了static已经无this指针了,直接用_data是不行的(原因:函数是在公共代码区,调用时不知道是哪个对象调用,需要this指针指明,但是这里由于加了static,没有this指针)。
解决方法:可以间接的用其他成员函数去调用_data。
private:void Excute(){_func(_data);return;}
public:// static void *threadroutine(void* args)// {// _func(_data);// return nullptr;// }static void *threadroutine(void* args){Thread<T> *self = static_cast<Thread<T>*>(args);//这时args里面要传一个类对象,利用这个对象去调用Excute从而访问_dataself->Excute();return nullptr;}
这种写法是 C++ 中使用类成员函数作为线程入口的标准范式,既满足了pthread_create对函数格式的要求(静态函数,无隐含this),又通过显式传递对象指针实现了对类内部资源的访问。