c++11封装thread库的方法示例

前言

c++11在语言层面上提供了对thread的支持,由于不同的平台提供了不同线程API,在语言层面提供了对thread的支持可以大大的减小代码移植的工作量。

本文将给大家详细介绍关于c++11封装thread库的相关内容,下面话不多说了,来一起看看详细的介绍吧

基本接口要求

要求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 保护的

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • C++11并发编程:多线程std::thread

    一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改.现在在C++11中只需使用语言层面的thread可以解决这个问题. 所需头文件<thread> 二:构造函数 1.默认构造函数 thread() noexcept 一个空的std::thread执行对象 2.初始化构造函数 template<class Fn, class... Args> explicit th

  • c++11封装thread库的方法示例

    前言 c++11在语言层面上提供了对thread的支持,由于不同的平台提供了不同线程API,在语言层面提供了对thread的支持可以大大的减小代码移植的工作量. 本文将给大家详细介绍关于c++11封装thread库的相关内容,下面话不多说了,来一起看看详细的介绍吧 基本接口要求 要求std::thread的构造函数 template< class Function, class... Args > explicit thread( Function&& f, Args&

  • 用pybind11封装C++实现的函数库的方法示例

    现有若干用C++编写的函数,为了能够用Python调用它们,可以通过pybind11将它们封装到一个Python模块中,在编写Python程序时只要导入该模块便能使用这些函数. 一.实现步骤 用C++函数实现函数功能: 编写头文件,将函数的声明包含在头文件中: 编写pybind11封装函数: 用Python编写setup脚本: 生成动态链接库pyd文件: 测试函数功能. 二.代码实现 1.用C++函数实现函数功能 //文件名:add.cpp extern "C" double add(

  • JavaScript使用链式方法封装jQuery中CSS()方法示例

    本文实例讲述了JavaScript使用链式方法封装jQuery中CSS()方法.分享给大家供大家参考,具体如下: 主要思路就是:返回this对象,将所获取的操作元素放入一个数组中.在原型中添加拓展方法 <html> <head> <title></title> </head> <body> <div id="one">aa</div> </body> <script typ

  • Vue自定义指令封装节流函数的方法示例

    节流函数是web前端开发中经常用到的一个开发技巧,在input实时搜索,滚动事件等,为了避免过多消耗性能,我们都会使用节流函数.在<JavaScript高级程序设计>一书中有这样的一个例子: function throttle (method, context) { clearTimeout((method.tId)) method.tId = setTimeout(function () { method.call(context) }, 100) } function resizeDiv

  • LocalStorage封装一次解决方法示例

    目录 1. 封装基础的方法 2. 使用的封装 3. 清除 总结 1. 封装基础的方法 首先对于localStorage做一个基础的封装,封装出 get .set .del 这几个基本的方法.这一步是方便后续的调用 新建一个storage文件 const storage = { get(key) { if (!key) { return null } key = key.toString(); const data = window.localStorage.getItem(key); retur

  • C++11中union的使用方法示例

    前言 union即为联合,它是一种特殊的类.通过关键字union进行定义,一个union可以有多个数据成员.例如 union Token{ char cval; int ival; double dval; }; c++11中union除了继承c语言的数据共享内存之外,行为上越来越像一个类,比如成员默认是public类型. 在C++11以后,很多基础语法都进行了修正.其中 union 的行为向类对象进行了发展,在兼容原有语法定义的基础上进行了扩充: union可以拥有成员函数(包含构造函数和析构

  • go语言实现markdown解析库的方法示例

    Blackfriday是在Go中实现的Markdown处理器.您可以安全地输入用户提供的数据,速度快,支持通用扩展(表,智能标点符号替换等),并且对于所有utf-8(unicode)都是安全的输入. 当前支持HTML输出以及Smartypants扩展. 使用 首先当然要引入: import github.com/russross/blackfriday 然后 output := blackfriday.MarkdownBasic(input) 这里input是[]byte类型,可以将markdo

  • 浅谈C++中thread库join和detach的区别

    目录 C++11中thread库join和detach的区别 线程状态 线程环境 join和detach的区别 总结 C++11中thread库join和detach的区别 线程状态 在一个线程的生存期中,可以在多种状态之间转换,不同的操作系统可以实现不同的线程模型,定义许多的线程状态,且每个状态还可以包含多个子状态.但大体来说,所有的操作系统有几种状态是通用的. 就绪态:参与调度,等待被执行,一旦被CPU选中,就立即开始执行. 运行态:占用CPU,正在被运行. 休眠态:暂不参与调度,等待特定的

  • python中pandas库中DataFrame对行和列的操作使用方法示例

    用pandas中的DataFrame时选取行或列: import numpy as np import pandas as pd from pandas import Sereis, DataFrame ser = Series(np.arange(3.)) data = DataFrame(np.arange(16).reshape(4,4),index=list('abcd'),columns=list('wxyz')) data['w'] #选择表格中的'w'列,使用类字典属性,返回的是S

  • python入门turtle库实现螺旋曲线图的方法示例

    记录turtle库中经常用到的函数. turtle.forward(distance)  画笔向前移动distance距离 turtle.backforward(distance)  画笔向后移动distance距离 turtle.right(degree)  绘制方向向右旋转degree度 turtle.exitonclick()  点击关闭图形窗口 turtle.penup()   抬起画笔,之后移动画笔不绘制形状 turtle.pendown()  落下画笔,之后移动画笔绘制形状 turt

随机推荐