ndk学习之c++语言基础复习----C++线程与智能指针
线程
线程,有时被称为轻量进程,是程序执行的最小单元。
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++线程与智能指针的更多相关文章
- ndk学习之C语言基础复习----虚拟内存布局与malloc申请
在这一次中来学习一下C语言的内存布局,了解它之后就可以解释为啥在用malloc()申请的内存之后需要用memset()来对内存进行一下初始化了,首先来了解一下物理内存与虚拟内存: 物理内存:通过物理内 ...
- ndk学习之c++语言基础复习----C++容器、类型转换、异常与文件流操作
继续来复习C++,比较枯燥,但是这是扎实掌握NDK开发的必经之路,不容小觑. 容器: 容器,就是用来存放东西的盒子. 常用的数据结构包括:数组array, 链表list, 树tree, 栈stack, ...
- ndk学习之c++语言基础复习----面向对象编程
关于面向对象编程对于一个java程序员那是再熟悉不过了,不过对于C++而言相对java还是有很多不同点的,所以全面复习一下. 类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程 ...
- ndk学习之C语言基础复习----基本数据类型、数组
关于NDK这个分类在N年前就已经创建了,但是一直木有系统的记录其学习过程,当然也没真正学会NDK的技术真谛,所以一直也是自己的一个遗憾,而如今对于Android程序员的要求也是越来越高,对于NDK也是 ...
- ndk学习之C语言基础复习----结构体、共用体与C++开端
自己实现sprintf功能: 关于C中的系统函数sprintf在上次[https://www.cnblogs.com/webor2006/p/7545627.html]学习中已经用到过了,这里再来回顾 ...
- ndk学习之C语言基础复习----指针、函数、预处理器
指针: 指针乃C.C++的灵魂之所在,所以有必要好好的复习复习.什么是指针?一句话来概括:“指针是一个变量,它的值是一个地址.”,其中指针变量的声明有如下三种形式: 其中第一种是被推荐的写法. 其中还 ...
- MySQL学习笔记_8_SQL语言基础复习
SQL语言基础复习 一.概述 SQL语句注释方式 1)以"#"开头直到行尾的所有内容都是注释 2)以"--"(--后还有一个空格)开头直到行尾的所有内容都是注释 ...
- Java学习笔记:语言基础
Java学习笔记:语言基础 2014-1-31 最近开始学习Java,目的倒不在于想深入的掌握Java开发,而是想了解Java的基本语法,可以阅读Java源代码,从而拓展一些知识面.同时为学习An ...
- C语言基础复习总结
C语言基础复习总结 大一学的C++,不过后来一直没用,大多还给老师了,最近看传智李明杰老师的ios课程的C语言入门部分,用了一周,每晚上看大概两小时左右,效果真是顶一学期的课,也许是因为有开发经验吧, ...
随机推荐
- 最新 阿里java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.阿里等10家互联网公司的校招Offer,因为某些自身原因最终选择了阿里.6.7月主要是做系统复习.项目复盘.LeetCode ...
- [转帖]阿里云VS腾讯云 谁才是中国未来的云计算之王?
阿里云VS腾讯云 谁才是中国未来的云计算之王? https://www.qianzhan.com/analyst/detail/220/191008-f05009f6.html 吴小燕• 2019-1 ...
- Redis 常用命令学习二:字符串类型命令
1.赋值与取值命令 127.0.0.1:6379> set foo helloredis OK 127.0.0.1:6379> get foo "helloredis" ...
- 程序计数器(关于java虚拟机内存的那些事)
<深入理解java虚拟机> 读书感悟 作者:淮左白衣 --------------写于2018年4月9日17:44:48 关于java虚拟机内存的那些事之程序计数器 关于java虚拟机内存 ...
- Appium移动端自动化测试--元素操作与触摸动作
常见自动化动作支持 click sendKeys swipe touch action 元素操作 1.click()点击操作 也可以用tab实现点击操作 driver.find_element_by_ ...
- logstash grok nginx log
#cat logstash.conf input { file { path => "/alidata/logs/nginx/appapi.dayutang.cn.access*.lo ...
- 数据类型 _python
字符串 str # a ="asd bfg" # print(a.capitalize()) #首字母大写 # print(a.title()) #每个单词首字母大写 # prin ...
- AttnGAN: Fine-Grained Text to Image Generation with Attentional Generative Adversarial Networks 笔记
AttnGAN: Fine-Grained Text to Image Generation with Attentional Generative Adversarial Networks 笔记 这 ...
- sublime text 2 + Dev-C++/MinGW 组合配置更方便快捷的 C/C++ 编译环境
首先看一下配置后的效果: 1.直接在底部文本框中显示运行结果(不需要从键盘输入的时候使用): 2.在cmd中运行结果(需要从键盘输入的时候使用): 快捷键说明: 运行: 在底部文本栏显示结果:Ctrl ...
- mybatis相关知识积累
mybatis Statement Statement对象用于将 SQL 语句发送到数据库中. 实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL语句的包容器: Stateme ...