多线程在很多地方都是必须要掌握的方法,这里先说一下,thread对象的参数传递问题
join()函数有两个作用,①、等待子线程执行完毕,主线程才结束执行;②、清理子线程相关的存储器,是std::thread不再与子线程相关联,释放子线程中的资源
join函数需要考虑的问题是,什么时候写join函数,如果在使用join函数之前,程序因为异常问题导致终止,没有调用join函数,导致内存泄露问题等等
detach()函数,让线程在后台运行主,意味着线程不能与之产生直接交互,后台线程的归属和控制都由C++运行时库处理。
detach函数需要考虑的问题是,确保子线程中的参数必须为对象的复制,因为可能主线程退出导致临时对象实现,子线程对象相继实现,出现不可预料的问题。
正如上面的初始化构造函数,我们传递参数将参数依次放在初始化构造函数中能够即可
对于x,使用的是引用传递,但是数字对象地址在主线程和子线程中地址不同。要在子线程中共享数据x,即地址相同,必须使用std::ref进行修饰,下面再在类对象作为参数传递时会有更详细说明
这样可以将参数传递到子线程中,并且我们可以发现子线程中的字符对象地址和传递进入的字符地址是相同的,所以我们可以推断指针这里使用的是浅层拷贝,两个指针指向的是同一个地址,所以这里的字符串时共享的,我们这里可以这样解决:
这里在子线程的函数参数中使用的是const string的引用,这样就首先在函数中将char*隐式转换为string,然后将string传送到子线程中进行操作
但是如果使用detach函数,还是有可能会产生问题,因为不确定什么时候进行饮食转换,可能在主线程结束后,隐式转换还没有开始,mybuff就已经失效了,这样依然会产生不可预料的结果。
在主线程中进行显示转换,这样可以保证一定可以在主线程中进行显示转换:
下面我们就对上面的说法进行验证:
这样我们发现,隐式转换是在子线程中进行的,但是我们只要增加显示转换后:
首先对象现在主线程中进行构造,并且将拷贝对象传到子线程中,实现对象的分离,所以这样即使在最后使用detcah函数,也不会早场引用已经析构的对象。
如果需要将类对象作为参数,需要在类中重载()运算符。栗子如下:
可以看到,函数对象首先在主线程中做一次拷贝构造,然后将拷贝后的对象传入线程中,在子线程中对对象进行修改也不会影响主线程中的对象
考虑一下:如果我们将first.join()换成first.detach(),这里会不会因为主线程提前退出,对象a提前销毁,对子线程中的对象造成影响?
正如我们上面解释的,传入子线程中的是在主线程中复制的对象,所以这里我们可以使用detach和join作用是相同的。
如果要将主线程对象本身传入子线程中,我们需要在传入参数中添加std::ref(a)即可,这里就必须要使用first.join(),防止出现上面所说的问题。
首先说明:因为程序中没有对数据进行保护,所以一定会出现错误,出现错误的时间不一定
我们这一要说的是类中函数作为线程参数,我们这里还需要传递一个类对象,因为我们知道在类中的函数存在一个默认参数,就是对象本身this,所以这里要将对象传递进去。
unique_ptr
独享所有权(单个智能指针指向一块内存)
shared_ptr
共享所有权(多个智能指针指向同一块内存)
创建类型为T的智能指针 |
创建类型为T的智能指针(C++14) |
使用智能指针之后,就可以不用关心delete
的时机,这些都由智能指针帮忙释放。
重置:会delete所管理的指针 |
释放:返回被管理的指针,智能指针置空 |
转移被管理的指针给其他unique_ptr,本身置空 |
获取被管理的指针,智能指针仍在管理 |
注意:不能使用智能指针来接受智能指针的释放
该方法就是可以解决范例3中的报错情况。
注意:不能使用智能指针来接受智能指针的获取(智能指针在初始化时不能用其他智能指针的get()来初始化)
不难看出,当TESTPTR对象a被exe回收的时候,也会把TESTPTR_B的对象析构,防止内存泄露。
注意:智能指针unqiue_ptr中途中被get()后,被管理指针(iprt)在其他地方被delete,那么在unqiue_ptr就需要release被管理的指针(iprt),不然unqiue_ptr在被回收时会再次delete 被管理的指针(iprt)从而造成程序崩溃。
当指针交给智能指针管理之后,如果想要delete,就调用unqiue_ptr的reset就好
unqiue_ptr
不能通过拷贝构造生成,也不可用=运算符来赋值,只能通过移动来赋值。例子如下
有两块数据组成,一个是数据块(存放指针),一个是计数块(记录引用计数)
创建类型为T的智能指针 |
创建类型为T的智能指针(C++14) |
返回被管理的指针的引用计数 |
智能指针重置后,重新管理新的指针 |
智能指针在计数变为0的时候会调用析构函数的delete。但是管理数组指针的时候就有局限性,就需要使用自定义删除器。
回调函数 (参数为智能指针管理的数据类型)
lambda表达式 (lambda表达式其实就是上面的中的另外一种写法罢了)
一般情况下,开发过程中如果要用到数组一般是使用STL的vector容器来代替数组,也可以交给智能指针管理。这里我用的是自定义数据类型。
函数对象:自定义类型对()重载,也就是仿函数。注意仿函数和自定义的类要分开写,详情见下面遇到的问题。
问题描述:这两种情况使用自定义删除器,在创建智能指针的时候会额外构造对象!!虽然能正常释放……
eg1:智能指针中存放数组,数组存放自定义数据类型,使用函数对象作为自定义删除器来回收内存。
下图中红色方框都是问题所在
上述问题中主要的错误在于自定义数据类型和仿函数(函数对象)没有分开写,导致重载的()污染了原来的代码逻辑。
lambda:lambda是C++11的新特性,可以代替 函数或者函数对象
应为栈中的数据在超出作用域之后就会被程序回收,然后智能指针也会对这块数据
版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。