封装实现线程库
Thread.hpp==>开源c++项目头文件和源文件的写法
header only的开源代码,会使用.hpp文件,因为该文件允许将类的声明和方法实现放在一起。
系统编程和网络编程,底层都是c语言的,注定要用到c/c++混编,但有些系统函数要求传入的参数是不认识string类型的,所以建议一些IO接口还是用c语言的。
(void)n的作用
写 (void)n;
是因为assert只在debug模式下生效,在release模式下无效。那么n就是一个被定义了但未被使用的变量,在有些编译器下会有warning,这里就对n做了一个无害的操作但是能取消警告。
assert和if、异常如何选择
意料之中用assert,意料之外用if和异常。
定义线程调用函数的正确做法
版本1:
class Thread
{
public:
typedef std::function<void*(void*)> func_t; //定义了线程要执行的函数类型
public:
// 创建线程
void start()
{
int n = pthread_create(&_tid, nullptr, func_t, _args); //error
assert(n == 0); //保证线程创建成功
(void)n;
}
private:
pthread_t _tid; //线程id
std::string _name; //线程名
func_t _func; //线程要执行的函数
void* _args; //线程函数参数
};
由于我们定义的线程要执行的函数是C++的,int n = pthread_create(&_tid, nullptr, func_t, _args);
这一句代码会报错,因为系统函数他只认识c类型的函数,那我们想到方法,就是把这个函数再套一层c的外壳,版本2如下
class Thread
{
public:
typedef std::function<void*(void*)> func_t; //定义了线程要执行的函数类型
public:
void* start_routime(void* args)
{
return _func(args);
}
// 创建线程
void start()
{
int n = pthread_create(&_tid, nullptr, start_routime, _args); //error
assert(n == 0); //保证线程创建成功
(void)n;
}
private:
pthread_t _tid; //线程id
std::string _name; //线程名
func_t _func; //线程要执行的函数
void* _args; //线程函数参数
};
int n = pthread_create(&_tid, nullptr, start_routime, _args);
这句代码还是报错,为什么呢?因为此时start_routime函数是类内成员,就会有缺省参数,一个隐含的对象指针this,即void* start_routime(Thread* this, void* args);
,传给pthread_create的参数不对,所以依然报错,那解决方法是什么呢?加一个static修饰,得到了版本3如下
class Thread
{
public:
typedef std::function<void*(void*)> func_t; //定义了线程要执行的函数类型
public:
static void* start_routime(void* args)
{
return _func(args);//error
}
// 创建线程
void start()
{
int n = pthread_create(&_tid, nullptr, start_routime, _args);
assert(n == 0); //保证线程创建成功
(void)n;
}
private:
pthread_t _tid; //线程id
std::string _name; //线程名
func_t _func; //线程要执行的函数
void* _args; //线程函数参数
};
return _func(args);
开始报错,因为start_routime是静态方法,静态方法无法调用类的成员方法和成员变量,不过此处不能改成static func_t _func;
,因为我们希望达成的效果是每创建出来一个线程都能执行不同的任务,当_func是static时,就意味着用我封装出来的线程库创建出来的线程只会做一件事。解决方案1将函数定义在类外,然后用友元来访问类内成员,当然还有其他的解决方案,接下来用以下这个方案:
class Thread; //声明
class Context //设置一个上下文
{
public:
Thread* _this;
void* _args;
public:
Context(): _this(nullptr), _args(nullptr)
{}
~Context()
{}
};
class Thread
{
public:
typedef std::function<void*(void*)> func_t; //定义了线程要执行的函数类型
public:
static void* start_routime(void* args) //start_routime是类内成员,它的参数会有个this指针,要加个static确保只有1个参数
{
Context* ctx = (Context*)args;
ctx->_this->run(ctx->_args);
delete ctx;
}
void* run(void* args)
{
return _func(args);
}
// 创建线程
void start()
{
Context* ctx = new Context();
ctx->_this = this;
ctx->_args = _args;
int n = pthread_create(&_tid, nullptr, start_routime, ctx);
assert(n == 0); //保证线程创建成功
(void)n;
}
private:
pthread_t _tid; //线程id
std::string _name; //线程名
func_t _func; //线程要执行的函数
void* _args; //线程函数参数
};
相当于再次包装了一下线程调用的函数,至此,可以正常使用,全部代码见我的gitee库https://gitee.com/hepburn0504-yyq/linux-class/tree/master/2023_03_22_ThreadPackage。