内容简介:要求std::thread的构造函数但是OS的库函数定义为:主要是接口中的entry,本身使用void*根本没带类型信息,难点在于要做到模板暴露出类型从而可以通用化
基本接口要求
要求std::thread的构造函数
template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );
但是OS的库函数定义为:
error_code create_thread((void_or_error_code(*entry)(void *), void *data);
主要是接口中的entry,本身使用void*根本没带类型信息,难点在于要做到模板暴露出类型从而可以通用化
void_or_error_code entry_point(void *arbitrary_data);
第一个问题:把f和args统统打包在一起做成一个void *结构
我们得从void* 中获取函数指针和参数指针,首先来个结构体定义真实指针类型
struct thread_data_base
{
virtual ~thread_data_base(){}
virtual void run()=0;
};
需要一个tuple,用于保存f和args,这样我们就可以通过将void *data cast成thread_data_base *,然后调用其中的虚函数run来实际调用f(args…)
std::tuple<typename std::decay<F>::type, typename std::decay<ArgTypes>::type...> fp;
而entry函数实现效果大致如下,将结构体包装在该函数里面
void_or_error_code thread_entry(void *data) {
std::unique_ptr<thread_data_base> p((thread_data_base *)data);
p->run();
// return result of p->run() if error code is required
}
第二个问题:定义一个template,以适配不同类型的f和args
template<typename F, class... ArgTypes>
class thread_data : public thread_data_base
{
public:
thread_data(F&& f_, ArgTypes&&... args_): fp(std::forward<F>(f_), std::forward<ArgTypes>(args_)...) {}
private:
std::tuple<typename std::decay<F>::type, typename std::decay<ArgTypes>::type...> fp;
}
在这个template里有一个data member正是那个关键的tuple,其类型需要使用traits进行类型推理出来
第三个问题:把任意的f和args包装成一个thread_data_base *
定义创建函数可以将任意f和arg来创建一个void*结构体,用来被entry函数调用
template<typename F, class... ArgTypes>
inline thread_data_base *make_thread_data(F&& f, ArgTypes&&... args)
{
return new thread_data<typename std::remove_reference<F>::type, ArgTypes...>(std::forward<F>(f),
std::forward<ArgTypes>(args)...); // 啥时候释放?
}
第四个问题:如何处理Args…
难点在于如何通过一个f和args组成的tuple调用f(args…),使用get需要传入一个编译期常量
tp.get<0>()(tp.get<1>(), tp.get<2>(), tp.get<3>());
为了方便,我们想把数列当前项直接放在参数列表里,要不然还需要在内部找到数列的最后一项
template <std::size_t Ep, std::size_t Sp>
struct make_tuple_indices {...};
为了生成数列[Sp, Ep),我们要做的就是从Sp开始,递归的在已有数列后面加一项,直到满足条件(Sp==Ep),下面就是最后定义的泛化,递归,终止条件
template <std::size_t Sp, class IntTuple, std::size_t Ep> struct make_indices_imp;
template <std::size_t Sp, std::size_t... Indices, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<Indices...>, Ep>
{ typedef typename make_indices_imp<Sp+1, tuple_indices<Indices..., Sp>, Ep>::type type; };
template <std::size_t Ep, std::size_t... Indices>
struct make_indices_imp<Ep, tuple_indices<Indices...>, Ep>
{ typedef tuple_indices<Indices...> type; };
template <std::size_t Ep, std::size_t Sp=0>
struct make_tuple_indices {
typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type;
};
已经有了run,之所以需要再定义一个run2,Indices是一个template type,只能用一个template function接收,所以我们需要把run和run2拆开,run作为继承下来的虚函数做入口,run2接收Indices并用之前提到的方法调用f(args…)。
实际上thread_data_base接口就是实现了一个简化版的std::bind
静态检查工具:Clang thread safety annotations,添加安全注解:通过代码注解告诉编译器哪些成员变量和成员函数是受哪个 mutex 保护,防止遗漏线程安全的假设。用 GUARDED_BY 表明哪个成员变量是被哪个 mutex 保护的
以上所述就是小编给大家介绍的《c++11如何封装thread库》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 封装JDBC—非框架开发必备的封装类
- SpringBlade 2.3.2 发布,增加 OSS 封装及单元测试封装
- SpringBlade 2.3.2 发布,增加 OSS 封装及单元测试封装
- docker 封装 alinode
- 封装Apk签名工具
- axios封装笔记
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First HTML5 Programming
Eric Freeman、Elisabeth Robson / O'Reilly Media / 2011-10-18 / USD 49.99
What can HTML5 do for you? If you're a web developer looking to use this new version of HTML, you might be wondering how much has really changed. Head First HTML5 Programming introduces the key featur......一起来看看 《Head First HTML5 Programming》 这本书的介绍吧!