当前课程知识点:基于Linux的C++ >  第十四讲 线程编程 >  14.13 C++11线程库(五) >  LinuxCPP1413

返回《基于Linux的C++》慕课在线视频课程列表

LinuxCPP1413在线视频

LinuxCPP1413

下一节:LinuxCPP1414

返回《基于Linux的C++》慕课在线视频列表

LinuxCPP1413课程教案、知识点、字幕

接下来我们看第二种

带回来结果的策略

这就是期许

在C++11标准库里边

替我们提供了一个新的类模板

叫std::future

它的目的就是为了获取

异步操作的结果

延迟引发线程的异步操作异常

使用方法 格式也是固定的

首先你要定义一个期许类模板的

一个期许对象

然后使用std::async()这个函数的返回值

对它进行初始化

然后你调用期许对象的成员函数get()

获取那个线程的返回值

听上去三步操作就能搞定

OK 我们看代码

我们实现一个函数叫CalculateFactorial()

去计算阶乘的

传的是一个short int

因为阶乘的计算增长得很快

所以不需要太大的整数

如果n是大于20的

我们就抛出异常

范围错误 就区间错误

抛出异常

20的阶乘我们能算

21的阶乘我们就算不了了

越界了 整数就越界了

数字就太大了 OK

函数的返回值

当然是一个unsigned long int

OK 函数本身很简单

我们看主函数 short int n

初始化成20

我们定义一个期许对象f

std::future〈unsigned long int〉

这是这个期许类的型

定义期许对象f

把它初始化成

std::async( CalculateFactorial, n)

什么意思

我们异步执行这个线程函数CalculateFactorial()

传线程函数参数n 去执行这个线程

它就会调度运行

这是后台计算 做完了

我们就通过期许对象f

得到那个线程的结果

try unsigned long intr

初始化为f.get()

这就把这个CalculateFactorial()

这个函数的结果就拿到了

你就输出就OK了 简单吧

这是很典型一个期许对象

你就把它搞定了

期许对象有什么好处呢

就是这个线程函数如果引发了异常

那么这个异常不会在那个线程中处理

线程内部可以处理

但处理完以后正常情况下你应该引发

待会我们再解释

如果那个运行的线程引发了异常

那么这个异常将会被延迟到std::future::get()

或者std::future::wait()

这两个成员函数被调用的时候

才会被引发

也就是我们的这个线程(主线程)

去处理劳工线程(它那个后台线程)

引发的那个异常

你可以按照这样一个方式去实现

try unsignedlong intr

初始化为f.get()

然后catch

按照这个模式去处理

接下来一个就是承诺

你可以使用这样的一个类模板

来构造一个承诺对象

它的使用方法

跟刚才那个期许对象相比

使用起来要稍微复杂一点

首先你要创建承诺对象

构造它的一个对象

然后获取

那个承诺对象的相关的期许对象

在此之后你要创建自己的线程对象

并传递这个承诺对象进去

然后线程函数内部

会通过承诺模板类的成员函数

set_value()、set_value_at_thread_exit()、

set_exception()、set_exception_at_thread_exit()

这样的函数

设置线程的返回值或者异常

然后我们就可以通过期许对象

等待并获取异步操作的结果

你看它实际上要和期许对象

一块运作的

为什么它叫承诺呢

那叫期许呢 这就很典型

你让一个线程去做一个异步的操作

它未来呢会带给你一个结果

主线程期望得到这个结果

就是它有期许

它对未来你给我算出来那个结果

它实际上是有期许的

这就是站在主线程角度

我们看待这个问题

它对劳工线程有一个期许

“你会给我一个结果的”

对吧 这就是这个future

未来会得到它

那么这边呢

当你构造这个线程对象的时候

那主线程要希望从你这里

得到一个数据呀 对吧 OK

当我构造这个模式的时候

对劳工线程来讲 我就承诺你

我会给你一个结果

就是这个意思

两者实现的策略 你看

这实际上是不一样的

我们看怎么使用它

我们使用承诺来设置线程的返回值

CalculateFactorial()这个函数还跟刚才一样

我们要为它实现一个打包类

要封装 DoCalculateFactorial()

传递一个承诺对象的右值引用

传递一个short int

那个线程函数的参数

传递承诺对象

因为这个标准线程函数

是没有承诺对象的

所以我们要用承诺机制的话

必须传递一个承诺对象进去

OK 我们的主程序中

将会定义这个承诺对象

构造一个

然后得到它对应的期许对象

每个承诺都会有一个对应的期许

所以我们构造出这个承诺对象之后

就直接在构造出来的承诺对象上

调用它的get_future()这个成员函数

得到它对应的期许对象就OK了

这是C++11标准库做好的

你构造这个对象

调用它的期许函数

就能够得到它的期许对象

然后我们启动线程

创建一个线程对象

把这个CalculateFactorial()打包函数

DoCalculateFactorial传进行

传承诺对象

因为是右值引用

所以我们传递右值 std::move(p) 传递它

第三个参数传n值

线程一构造 我们detach()

分离它 不管它了

让它在后台跑就行了

然后我们try f.get()

从期许对象中获取这个线程的返回值

如果我拿到了这个线程的返回值

我就输出

否则那个线程就引发了异常了

所以这个时候我们就catch

抓住这个异常

我们处理这个异常 就OK了

所以你看到

对于期许对象来讲

我们实际上是期许从

后台线程中得到结果的

主要是在我们的主程序里要做的事情

而我们的承诺对象呢

那是线程在做的时候

要承诺给你一个结果的

如果你那个线程本身

并没有带有承诺对象的参数

那么你就必须为你那个线程函数

做一个封包 打包

搞一个打包函数

在这里面传一个承诺对象进去

然后我们构造这个承诺对象

然后你就可以在构造线程的时候

传递这个承诺对象

给这个线程函数的打包函数

线程函数的打包函数就会说

“我承诺我会给你一个结果的,

你未来就可以使用我的期许对象

获得那个结果”

就这个意思 实现上非常巧妙

那么我们的DoCalculateFactorial()怎么实现呢

代码其实也很简单

try pormise.set_value() 设定值

我承诺给你一个结果啊

怎么设定这个结果呢

那就是设置set_value()

这是一个设置这个线程返回值的函数

成员函数 你就调用它

pormise.set_value()

调用那个真正的线程函数CalculateFactorial(n)

就把这个结果设定进行

如果这个线程发生了全部的异常

不管是哪一个 捕获它

然后set_exception()成员函数调用

把这个当前的异常重新引发

你可以在前面做一些特定的处理

然后set_exception()

做这个成员函数的调用

重新引用这个当前的异常

一设置好这个异常以后

那么就可以在f.get()或f.wait()

那个期许对象获取那个值的时候

产生这个异常的引发动作

那个时候它就可以处理这个异常

这就是承诺的全部实现

基于Linux的C++课程列表:

第一讲 C/C++基本语法元素

-1.1 提纲

--LinuxCPP0101

-1.2 程序设计的基本概念

--LinuxCPP0102

-1.3 简单C/C++程序介绍

--LinuxCPP0103

-1.4 程序设计的基本流程

--LinuxCPP0104

-1.5 基本语法元素

--LinuxCPP0105

-1.6 程序设计风格

--LinuxCPP0106

-1.7 编程实践

--LinuxCPP0107

-第一讲 C/C++基本语法元素--编程实践提交入口

第二讲 程序控制结构

-2.1 提纲

--LinuxCPP0201

-2.2 结构化程序设计基础

--LinuxCPP0202

-2.3 布尔数据

--LinuxCPP0203

-2.4 分支结构

--LinuxCPP0204

-2.5 break语句

--LinuxCPP0205

-2.6 循环结构

--LinuxCPP0206

-2.7 编程实践

--LinuxCPP0207

-第二讲 程序控制结构--编程实践提交入口

第三讲 函数

-3.1 提纲

--LinuxCPP0301

-3.2 函数声明、调用与定义

--LinuxCPP0302

-3.3 函数调用栈框架

--LinuxCPP0303

-3.4 编程实践

--LinuxCPP0304

-第三讲 函数--编程实践提交入口

第四讲 算法

-4.1 提纲

--LinuxCPP0401

-4.2 算法概念与特征

--LinuxCPP0402

-4.3 算法描述

--LinuxCPP0403

-4.4 算法设计与实现

--LinuxCPP0404

-4.5 递归算法(一)

--LinuxCPP0405

-4.6 递归算法(二)

--LinuxCPP0406

-4.7 容错与计算复杂度

--LinuxCPP0407

-4.8 编程实践

--LinuxCPP0408

-第四讲 算法--编程实践提交入口

第五讲 程序组织与开发方法

-5.1 提纲

--LinuxCPP0501

-5.2 库与接口

--LinuxCPP0502

-5.3 随机数库(一)

--LinuxCPP0503

-5.4 随机数库(二)

--LinuxCPP0504

-5.5 作用域与生存期

--LinuxCPP0505

-5.6 典型软件开发流程(一)

--LinuxCPP0506

-5.7 典型软件开发流程(二)

--LinuxCPP0507

-5.8 编程实践

--LinuxCPP0508

-第五讲 程序组织与开发方法--编程实践提交入口

第六讲 复合数据类型

-6.1 提纲

--LinuxCPP0601

-6.2 字符

--LinuxCPP0602

-6.3 数组(一)

--LinuxCPP0603

-6.4 数组(二)

--LinuxCPP0604

-6.5 结构体

--LinuxCPP0605

-6.6 编程实践

--LinuxCPP0606

-第六讲 复合数据类型--编程实践提交入口

第七讲 指针与引用

-7.1 提纲

--LinuxCPP0701

-7.2 指针基本概念

--LinuxCPP0702

-7.3 指针与函数

--LinuxCPP0703

-7.4 指针与复合数据类型(一)

--LinuxCPP0704

-7.5 指针与复合数据类型(二)

--LinuxCPP0705

-7.6 字符串

--LinuxCPP0706

-7.7 动态存储管理(一)

--LinuxCPP0707

-7.8 动态存储管理(二)

--LinuxCPP0708

-7.9 引用

--LinuxCPP0709

-7.10 编程实践

--LinuxCPP0710

-第七讲 指针与引用--编程实践提交入口

第八讲 链表与程序抽象

-8.1 提纲

--LinuxCPP0801

-8.2 数据抽象(一)

--LinuxCPP0802

-8.3 数据抽象(二)

--LinuxCPP0803

-8.4 链表(一)

--LinuxCPP0804

-8.5 链表(二)

--LinuxCPP0805

-8.6 链表(三)

--LinuxCPP0806

-8.7 链表(四)

--LinuxCPP0807

-8.8 函数指针(一)

--LinuxCPP0808

-8.9 函数指针(二)

--LinuxCPP0809

-8.10 抽象链表(一)

--LinuxCPP0810

-8.11 抽象链表(二)

--LinuxCPP0811

-8.12 编程实践

--LinuxCPP0812

-第八讲 链表与程序抽象--编程实践提交入口

第九讲 类与对象

-9.1 提纲

--LinuxCPP0901

-9.2 程序抽象与面向对象

--LinuxCPP0902

-9.3 类类型

--LinuxCPP0903

-9.4 对象(一)

--LinuxCPP0904

-9.5 对象(二)

--LinuxCPP0905

-9.6 类与对象的成员(一)

--LinuxCPP0906

-9.7 类与对象的成员(二)

--LinuxCPP0907

-9.8 类与对象的成员(三)

--LinuxCPP0908

-9.9 继承(一)

--LinuxCPP0909

-9.10 继承(二)

--LinuxCPP0910

-9.11 继承(三)

--LinuxCPP0911

-9.12 多态(一)

--LinuxCPP0912

-9.13 多态(二)

--LinuxCPP0913

-9.14 编程实践

--LinuxCPP0914

-第九讲 类与对象--编程实践提交入口

第十讲 操作符重载

-10.1 提纲

--LinuxCPP1001

-10.2 四则运算符重载(一)

--LinuxCPP1002

-10.3 四则运算符重载(二)

--LinuxCPP1003

-10.4 关系与下标操作符重载

--LinuxCPP1004

-10.5 赋值操作符重载(一)

--LinuxCPP1005

-10.6 赋值操作符重载(二)

--LinuxCPP1006

-10.7 赋值操作符重载(三)

--LinuxCPP1007

-10.8 赋值操作符重载(四)

--LinuxCPP1008

-10.9 赋值操作符重载(五)

--LinuxCPP1009

-10.10 流操作符重载(一)

--LinuxCPP1010

-10.11 流操作符重载(二)

--LinuxCPP1011

-10.12 流操作符重载(三)

--LinuxCPP1012

-10.13 操作符重载总结

--LinuxCPP1013

-10.14 编程实践

--LinuxCPP1014

-第十讲 操作符重载--编程实践提交入口

第十一讲 泛型编程

-11.1 提纲

--LinuxCPP1101

-11.2 泛型编程概览

--LinuxCPP1102

-11.3 异常处理机制(一)

--LinuxCPP1103

-11.4 异常处理机制(二)

--LinuxCPP1104

-11.5 运行期型式信息(一)

--LinuxCPP1105

-11.6 运行期型式信息(二)

--LinuxCPP1106

-11.7 模板与型式参数化

--LinuxCPP1107

-11.8 题外话:术语翻译

--LinuxCPP1108

-11.9 泛型编程实践(一)

--LinuxCPP1109

-11.10 泛型编程实践(二)

--LinuxCPP1110

-11.11 泛型编程实践(三)

--LinuxCPP1111

-11.12 泛型编程实践(四)

--LinuxCPP1112

-11.13 泛型编程实践(五)

--LinuxCPP1113

-11.14 泛型编程实践(六)

--LinuxCPP1114

-11.15 泛型编程实践(七)

--LinuxCPP1115

-11.16 泛型编程实践(八)

--LinuxCPP1116

-11.17 泛型编程实践(九)

--LinuxCPP1117

-11.18 泛型编程实践(十)

--LinuxCPP1118

-11.19 编程实践

--LinuxCPP1119

-第十一讲 泛型编程--编程实践提交入口

第十二讲 Linux系统编程基础

-12.1 提纲

--LinuxCPP1201

-12.2 程序执行环境(一)

--LinuxCPP1202

-12.3 程序执行环境(二)

--LinuxCPP1203

-12.4 程序执行环境(三)

--LinuxCPP1204

-12.5 程序执行环境(四)

--LinuxCPP1205

-12.6 输入输出(一)

--LinuxCPP1206

-12.7 输入输出(二)

--LinuxCPP1207

-12.8 文件系统

--LinuxCPP1208

-12.9 设备

--LinuxCPP1209

-12.10 库(一)

--LinuxCPP1210

-12.11 库(二)

--LinuxCPP1211

-12.12 makefile文件(一)

--LinuxCPP1212

-12.13 makefile文件(二)

--LinuxCPP1213

-12.14 makefile文件(三)

--LinuxCPP1214

-12.15 编程实践

--LinuxCPP1215

-第十二讲 Linux系统编程基础--编程实践提交入口

第十三讲 进程编程

-13.01 提纲

--LinuxCPP1301

-13.02 进程基本概念

--LinuxCPP1302

-13.03 信号

--LinuxCPP1303

-13.04 进程管理(一)

--LinuxCPP1304

-13.05 进程管理(二)

--LinuxCPP1305

-13.06 进程管理(三)

--LinuxCPP1306

-13.07 进程间通信(一)

--LinuxCPP1307

-13.08 进程间通信(二)

--LinuxCPP1308

-13.09 进程间通信(三)

--LinuxCPP1309

-13.10 进程间通信(四)

--LinuxCPP1310

-13.11 进程池

--LinuxCPP1311

-13.12 编程实践

--LinuxCPP1312

-第十三讲 进程编程--编程实践提交入口

第十四讲 线程编程

-14.1 提纲

--LinuxCPP1401

-14.2 线程基本概念

--LinuxCPP1402

-14.3 线程管理(一)

--LinuxCPP1403

-14.4 线程管理(二)

--LinuxCPP1404

-14.5 线程管理(三)

--LinuxCPP1405

-14.6 线程管理(四)

--LinuxCPP1406

-14.7 线程同步机制(一)

--LinuxCPP1407

-14.8 线程同步机制(二)

--LinuxCPP1408

-14.9 C++11线程库(一)

--LinuxCPP1409

-14.10 C++11线程库(二)

--LinuxCPP1410

-14.11 C++11线程库(三)

--LinuxCPP1411

-14.12 C++11线程库(四)

--LinuxCPP1412

-14.13 C++11线程库(五)

--LinuxCPP1413

-14.14 编程实践

--LinuxCPP1414

-第十四讲 线程编程--编程实践提交入口

第十五讲 网络编程

-15.1 提纲

--LinuxCPP1501

-15.2 Internet网络协议

--LinuxCPP1502

-15.3 套接字(一)

--LinuxCPP1503

-15.4 套接字(二)

--LinuxCPP1504

-15.5 编程实践

--LinuxCPP1505

-第十五讲 网络编程--编程实践提交入口

课程文档

-课程PDF文件

LinuxCPP1413笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。