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

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

LinuxCPP1411在线视频

LinuxCPP1411

下一节:LinuxCPP1412

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

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

接下来的一个就是条件变量类

那个类的名字叫condition_variable

或者condition_variable_any

第一个是必须和unique_lock配对用的

第二个是更加通用的这样的条件变量

可以和任意型式的互斥配合

要比第一个使用的时候呢

多一些额外的开销 其它没什么

它主要用于多线程之间的同步

它可以阻塞一个或多个的线程

直到它收到来自其它线程的一个通知

说你等待的那个特定的条件好了

那个时候它才能够被唤醒

当然有的时候

是有可能产生一个虚假的唤醒

那个条件没好 可能会被唤醒

所以碰到这个时候

你还需要一个特别的量

来保存它条件是不是真的好了

就注意这一点

这两个类 成员函数都一样的

你用的时候没有什么特别差别

特别注意 要在等待这个条件变量前

你要必须获得那个锁

所有这些东西都是需要互斥的

在条件变量类里

定义了一系列的成员函数

比如讲notify_one()

就通知一个等待线程

说你等待的条件得到满足了

至于通知哪一个

操作系统选择

成员函数notify_all()

就通知全部的线程

你等待这个条件好了

哪一个线程会被调度

操作系统决定

还有wait()

你如果需要等待一个特定的条件

那么wait()就会阻塞当前的线程

直到有人通知你

你等待的那个条件好了

就是这个意思

还有两个函数

一个叫wait_for()

一个叫wait_until()

阻塞当前的进程

直到它被唤醒或者到达指定的时长

这叫wait_for()

等待那么长时间

或者wait_until()

直到指定的时点

它就会被唤醒

就这个wait_until()

我们来看怎么用

条件变量类必须和互斥一块用

我们有一个互斥x

然后定义一个条件变量cond

有一个bool量ready

来表示它是不是就绪的

一开始的时候设定成false

写了一个函数bool IsReady()

它是一个谓词函数了

返回值是一个bool量

然后return我们的value值

这个函数很简单

我们的线程函数run()

定义一个unique_lock

使用互斥作为它的模板实际参数

传进去以后定义一个unique_lock

独一锁

对象的名字叫locker(x)

互斥传进去构造出来 锁定

当没有ready的时候

我们cond.wait() 等待它

等待它的状态得到满足

传的参数就是锁定那个互斥的

那个独一锁

传的就是它 condition.wait( locker)

为啥呀

条件变量本身好多个线程要用啊

访问它本身就需要锁定

锁的就是它

用互斥来锁定它的嘛

那我们有一个锁locker

就是管理那个互斥对象的嘛

所以在这里cond.wait()

传的参数

就是那个互斥对象的管理对象

locker 传的就是它

这两行呢

等价于你使用这个代码cond.wait()

第一个参数传locker

第二个参数传IsReady

也就是说wait()这个函数本身

是双版本的

你如果只传一个 那么它就等

如果传第二个参数呢

那就是一个谓词函数

它就在满足这个条件的时候

它就退出

等到了这个条件了嘛

它不就唤醒了嘛

就这个意思

我们看主函数

我们定义8个线程

8个

然后调用thread构造函数

构造这8个线程

接下来在一个复合块内

用unique_lock构造一个独一锁

ready设成true

然后cond.notify_all()

通知所有 告诉它们所有线程

好了 所有的数据准备完毕

你们开始跑吧

“一、二、三 开始!”

就这个意思

做完了这些 它们都跑完了

我们就可以t.join()

一个线程 一个线程地全部都销毁

等待它结束 销毁它

清除它的工作

清除它最后的资源 就OK了

注意我这里面使用是新的

C++11的for循环架构

这是基于区间的循环模式

for( auto & t: threads)

就是对于属于这个threads

集合里的任意的t做循环体

t的型是什么呢

是一个对自动型的引用

auto就是由编译器来决定

这个t的型是什么

auto就是这个意思

接下来呢就是原子型式

你可以使用atomic这个模板

来定义原子对象

什么叫原子对象

原子对象就是提供一种轻量级的

支持一个单变量上的

一个原子操作的这种东西

叫原子型

所以它不能够处理复杂的数据结构

往往只能处理一个单一的一个变量

而且大部分时候那个单一的变量存储空间

不会超过一个整数的大小

可以使用预定义的一些标准原子型

你比如说atomic_bool、atomic_char、

atomic_int等等

你可以使用

你也可以使用atomic那个模板

来定义原子型

体化它特定的型就OK了

特定的一些原子型

它都有一些支持的特定的操作

不同的型支持的操作是不一样的

在这里面我们简单地列了一个表格

具体的原子型我们看这样的一个例子

在这里我定义了两个函数

一个函数叫做AddAtomically()

一个叫Add()

一个是原子加 一个是普通加法

你看我们这里边有两个整数

一个是普通整数

一个是原子整数

是atomic〈int〉

用这个模式去定义的

n是普通整数

a是我们的原子整数

然后我们构造16个线程

8个线程呢 是调用原子加

8个线程呢 是调用普通加

它们调用的操作是不一样的

严格讲起来 我这里面的赋值

包括前面那个 看

要用右值拷贝

右值引用那个右值赋值过去

这叫移动语义

要使用这个模式赋值 完成

然后等待这些线程做完

然后你就输出这个结果

你多运行几次

你观察一下它的运行

其实你就会明白

每次执行的时候

执行原子加法操作的线程

得到的结果总是一致的

而执行非原子操作的线程

得到的结果可能是不一样的

它有时是会发生变化的

而且特别明显

特别注意这一条

所以原子型的操作和非原子型的操作

它是不一样的

要特别注意这一条

基于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文件

LinuxCPP1411笔记与讨论

也许你还感兴趣的课程:

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