线程

线程,有时被称为轻量进程,是程序执行的最小单元。

C++11线程:

我们知道平常谈C++线程相关的东东基本都是基于之后要学习的posix相关的,其实在C++11有自己新式创建线程的方法,所以先来看一下,看在C++11中如何来创建一个线的,如下:

比较简单,直接过~

POSIX线程【常用】:
POSIX 可移植操作系统接口,标准定义了操作系统应该为应用程序提供的接口标准。相比C++ 11的线程这种方式就要麻烦一些,下面来用看一下它的创建方式:

下面来使用一下:

然后第三个参数则为线程运行的函数地址,其参数类型为:

也就是是个函数指针,该函数返回一个void*指针,接收一个void*参数,所以咱们来定义一下该参数:

最后一个参数则是运行函数的参数,所以咱们也来定义一下:

编译运行:

  • 线程属性:
    线程具有属性,用 pthread_attr_t 表示,目前咱们在创建线程时这块的参数是传的0,如下:

    接下来咱们来定义一下该参数:

    那设置该属性有啥用呢,主要是有以下两种用处,如下:

    ①、分离线程【了解既可】:

    线程创建默认是非分离的,当pthread_join()函数返回时,创建的线程终止,释放自己占用的系统资源

    分离线程是指不能被其他线程等待,pthread_join无效,线程自己玩自己的。

    在设置属性之前咱们先来看一下目前程序的行为:

    在默认属性的情况下我们的join()是能正常等到线程结束之后才结束的,如下:

    接下来设置成分离线程属性,如下:

    再来编译运行:

    可以看到我们的join()已经不起作用了,这个了解一下既可,在Android NDK中实际中基本上很少用到它。

    ②、调度策略与优先级【实际用得少,了解既可】:
    这里直接贴出用法:

  • 线程同步:
    多线程同时读写同一份共享资源的时候,可能会引起冲突。需要引入线程“同步”机制,即各位线程之间有序地对共享资源进行操作。
    下面先看下有线程同步问题的代码:

    编译运行:

    接下来可以给程序加入互斥锁,具体做法如下:

    此时再编译运行:

    其实跟java的synchronized是一样的效果。

  • 条件变量:
    条件变量是线程间进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立",从而唤醒挂起线程。
    下面使用它来完成一个生产者消费者模型,也就是如果发现队列里没有数据可消费了则等待生产者进行生产,一旦生产了数据则消费者立马消费,具体实现如下:

    接下来实现具体的插入元素及取出元素:

    但是!!目前实现还不尽人意,当队列中没有数据时,目前方法是直接就结束,并没有一个等待的过程,在Java中我们可以使用wait和notify机制达到,而在C++中可以使用条件变量来搞定,具体做法如下:

    同样的条件变量也是需要初始化和销毁的,下面来使用它:

    接下来咱们来测试一下:

    编译运行:

    注意:条件变量等待会让cpu释放锁,而不是一直在背后运行,能提高性能。

智能指针
自C++11起,C++标准库提供了两大类型的智能指针。为啥要有智能指针呢?下面先来用程序来说明一下背景:

但是!!

对于堆上的内存都需要我们手动去释放内存,如下:

也就是在实际开发中会存在堆中申请的内存可能会忘记手动释放而造成内存泄漏,所以智能指针的出现就是用来解决这个问题的。

shared_ptr:
操作引用计数实现共享式拥有的概念。多个智能指针可以指向相同的对象,这个对象和其相关资源会在最后一个被销毁时释放。
下面咱们来使用一下它:

其实它内部是实现了引用计数,像下面这个程序:

而当testPtr()方法执行完之后,shared_ptr1和shared_ptr2都会回收,因为是栈上的内在,所以当shared_ptr1被回收时其引用计数由2就会变为1,同样的shared_ptr2被回收时其引用计数就由1又变回了0,而当引用计数为0时则会delete到所引用的A对象了。

注意:虽然使用shared_ptr能够非常方便的为我们自动释放对象,但是还是会出现一些问题。最典型的就是循环引用问题。

下面来看一下下面的代码:

结果一切正常,没有内存泄漏,但是如果下面这样来改就会有问题了,如下:

所以基于这个问题,weak_ptr就诞生了。

  • weak_ptr:

    weak_ptr是为配合shared_ptr而引入的一种智能指针。主要用于观测资源的引用情况。

    它的构造和析构不会引起引用记数的增加或减少。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象。

    配合shared_ptr解决循环引用问题,下面来对上面有问题的代码进行修改,如下:


    注意:weak_ptr 提供expired 方法等价于 use_count == 0,当expired为true时,lock返回一个存储空指针的shared_ptr。

unique_ptr:
实现独占式引用,保证同一时间只有一个智能指针指向内部对象。什么意思?看代码:

自定义智能指针:
为了更加深入的理解“shared_ptr”这个智能指针的原理,咱们动手来写一个类似效果的智能指针,先新建一个头文件定义大体的框架:

还得实现一个拷贝构造函数:

咱们来使用一下:

那如果调用时这样来写呢?

此时就需要重载一下=号运算符了,如下:

编译运行:

下面再来理解一下这段代码,为啥要引用计数要减1,如下:

这时因为:

因为在默认构造中是这么写的:

然后此时要将该对像进行如下新的赋值:

那在赋值之前,不得先将shared_ptr2这个新对象中的值给清掉么,这样说还不太明显,下面来改造一下程序就立马能明白了:

此时shared_ptr2又要引用shared_ptr1,如果不先释放shared_ptr2原来的值,那不就造成了a2有内存泄漏么,试一下:

编译运行:

所以还是将代码还原,再运行:

编译运行:

总之:其实智能指针底层就是用了引用计数,并利用栈内存出方法必然会释放的原因来实现的。

部分C++11、14特性【不一定自己会使用这些特性,但是别人使用到了需要能读懂】

nullptr:
nullptr 出现的目的是为了替代 NULL。 C++11之前直接将NULL定义为 0。

看下代码:

所以为了解决这个问题,可以用nullptr,如下:

类型推导:
C++11 重新定义了auto 和 decltype 这两个关键字实现了类型推导,让编译器来操心变量的类型。

看下代码:

而对于vector的遍历也可以用auto来简化,具体如下:

基于范围的for循环:
实际上就是foreach,新式写法可以这样写了:

Lambda:【懂java8的应该这块不难理解】

匿名函数,即没有函数名的函数

完整形式:

捕获外部变量列表mutable exception->返回类型 { 函数体 }

mutable:在外部变量列表以值来捕获时,无法修改变量的值,加上mutable表示可修改(不会影响外部变量)

这里以创建线程为例,原来的方式我们已经比较清楚了,看一下使用Lambda表达式简化成了啥样:

其中这块还有一些其它的形式:

如果我们想在线程中引用外部的变量,目前的写法是不行的,如下:

此时如果使用它:

就可以正常引用了,如下:

但是此时如果我们想在线程中去修改外部变量的值呢?

此时另外一种形式就发挥作用了,如下:

修改一下代码:

此外如果方法有值返回可以这样写:

但是注意:这里的"-> auto"自动推导在C++11是不支持的,而在C++14中是支持的。

ndk学习之c++语言基础复习----C++线程与智能指针的更多相关文章

  1. ndk学习之C语言基础复习----虚拟内存布局与malloc申请

    在这一次中来学习一下C语言的内存布局,了解它之后就可以解释为啥在用malloc()申请的内存之后需要用memset()来对内存进行一下初始化了,首先来了解一下物理内存与虚拟内存: 物理内存:通过物理内 ...

  2. ndk学习之c++语言基础复习----C++容器、类型转换、异常与文件流操作

    继续来复习C++,比较枯燥,但是这是扎实掌握NDK开发的必经之路,不容小觑. 容器: 容器,就是用来存放东西的盒子. 常用的数据结构包括:数组array, 链表list, 树tree, 栈stack, ...

  3. ndk学习之c++语言基础复习----面向对象编程

    关于面向对象编程对于一个java程序员那是再熟悉不过了,不过对于C++而言相对java还是有很多不同点的,所以全面复习一下. 类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程 ...

  4. ndk学习之C语言基础复习----基本数据类型、数组

    关于NDK这个分类在N年前就已经创建了,但是一直木有系统的记录其学习过程,当然也没真正学会NDK的技术真谛,所以一直也是自己的一个遗憾,而如今对于Android程序员的要求也是越来越高,对于NDK也是 ...

  5. ndk学习之C语言基础复习----结构体、共用体与C++开端

    自己实现sprintf功能: 关于C中的系统函数sprintf在上次[https://www.cnblogs.com/webor2006/p/7545627.html]学习中已经用到过了,这里再来回顾 ...

  6. ndk学习之C语言基础复习----指针、函数、预处理器

    指针: 指针乃C.C++的灵魂之所在,所以有必要好好的复习复习.什么是指针?一句话来概括:“指针是一个变量,它的值是一个地址.”,其中指针变量的声明有如下三种形式: 其中第一种是被推荐的写法. 其中还 ...

  7. MySQL学习笔记_8_SQL语言基础复习

    SQL语言基础复习 一.概述 SQL语句注释方式 1)以"#"开头直到行尾的所有内容都是注释 2)以"--"(--后还有一个空格)开头直到行尾的所有内容都是注释 ...

  8. Java学习笔记:语言基础

    Java学习笔记:语言基础 2014-1-31   最近开始学习Java,目的倒不在于想深入的掌握Java开发,而是想了解Java的基本语法,可以阅读Java源代码,从而拓展一些知识面.同时为学习An ...

  9. C语言基础复习总结

    C语言基础复习总结 大一学的C++,不过后来一直没用,大多还给老师了,最近看传智李明杰老师的ios课程的C语言入门部分,用了一周,每晚上看大概两小时左右,效果真是顶一学期的课,也许是因为有开发经验吧, ...

随机推荐

  1. 【长期更新】Leetcode刷题心得与思考

    1.递归与动态规划的思考 Leetcode第95题 递归问题最重要的问题是想明白函数的作用是什么? 这个例子中函数的返回值就是给定a-b这个区间的数字,返回它所有可能的Tree,此时你不需要明白具体怎 ...

  2. Spring 使用日期类型

    1. 数据层数据类型依赖包  java.time.LocalDate 2.pom.xml添加依赖 <dependency> <groupId>org.thymeleaf.ext ...

  3. MyBatis框架总结

    一. MyBatis简介 MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索.MyBati ...

  4. 封装一个Model或者Vender类

    Model <?php /** * User: Eden * Date: 2019/3/21 * 共有内容 */ class WxPayModel extends Model { protect ...

  5. ORA-01078: failure in processing system parameters LRM-00109: could not open parameter file '/u01/app/oracle/product/19.2.0/db_1/dbs/initsanshi.ora'报错

    本人是在Linux安装Oracle19C之后,启动数据库时,XSHELL命令行窗口报的该错误,看了几个解决方案之后,总结如下 从字面的意思来看,是在dbs目录当中没有这个initsanshi.ora文 ...

  6. Java基础---Java变量

    变量:程序运行期间,内容可以发生改变的量. 创建一个变量并且使用的格式: 数据类型 变量名称;         // 创建了一个变量 变量名称 = 数据值;           // 赋值,将右边的数 ...

  7. JMeter断言介绍

    (1)作用:用于检查测试中得到的响应数据等是否符合预期,用以保证性能测试过程中的数据交互与预期一致 (2)目的:在request的返回层面增加一层判断机制:因为request成功了,并不代表结果一定正 ...

  8. HTML 是什么?

    HTML 指的是超文本标记语言(英语:HyperText Markup Language),是用来描述网页的一种语言. HTML 不是一种编程语言,而是一种标记语言,它有一套标记标签 . HTML 使 ...

  9. 2019CCPC网络赛——array(权值线段树)

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=6703 题目大意: 给出一个n(n<1e5)个元素的数组A,A中所有元素都是不重复的[1,n]. 有 ...

  10. STM32的I2C通讯过程

    使用I2C外设通讯时,在通讯的不同阶段它会对“状态寄存器(SR1 及SR2)”的不同数据位写入参数,通过读取这些寄存器标志来了解通讯状态. 1.主发送器 可使用STM32标准库函数来直接检测这些事件的 ...