C++多线程基础学习笔记(三)
一、detach()大坑
上一篇随笔(二)中提到detach()是用来分离主线程和子线程的,那么需要考虑一个问题,就是如果主线程跑完了,主线程中定义的变量就会被销毁(释放内存),这时回收变量仍作为参数传入子线程,那么就会出现问题,下面用一个例子详细说明。
#include <iostream>
#include <string>
#include <thread>
using namespace std; void MyThread(const int& a, char* str)
{
cout << a << endl;
cout << str << endl;
}
int main()
{ int n = ;
char str_m[] = "hello wrold";
thread MyThreadObj(MyThread, n, str_m);
if (MyThreadObj.joinable())
{
MyThreadObj.detach();
}
cout << "main_thread" << endl;
system("pause");
return ;
}
由监视图可知,实参n和形参a的地址并不同,所以实际是值传递,并因此最好不要用引用,直接用值传递就行了。
主线程的str_m和str的地址却相同,那么当子线程和主线程分离时,就会出现问题。这里讲一个改进的方法,把形参char* str改成const string& str,即把传进来的参数隐式地转换成一个(构造了)string对象,会发现主线程的str_m和子线程形参str的地址是不同的,但实际上问题还是存在,如果在在传递主线程的参数str_m前,str_m就被回收了,一个被回收的变量作为参数结果可想而知。所以还要再改多一步,就是在main()中实参str_m改成string(str_m),先构造一个string对象,再将这个对象作为参数传入子线程,这时又会有疑问,难道不会出现在string(str_m)前str_m就被系统回收了吗?答案是不会的,测试方法这里不细说了。
下面是改进后的代码
#include <iostream>
#include <string>
#include <thread>
using namespace std; void MyThread(int a, const string& str)
{
cout << a << endl;
cout << str << endl;
}
int main()
{ int n = ;
char str_m[] = "hello wrold";
thread MyThreadObj(MyThread, n, string(str_m));
if (MyThreadObj.joinable())
{
MyThreadObj.detach();
}
cout << "main_thread" << endl;
system("pause");
return ;
}
二、std::this_thread::get_id()
线程id,每个线程都有自己的线程id,各个id都不同,获取线程id方法为std::this_thread::get_id()
#include <iostream>
#include <string>
#include <thread>
using namespace std;
class CA
{
public:
int a;
CA(int m) :a(m)
{
cout << "构造函数执行 " << endl;
}
CA(const CA&m) :a(m.a)
{
cout << "拷贝构造函数执行 " << endl;
}
};
void MyThread(const CA&cc)
{
cout << "子线程id:" << this_thread::get_id() << endl;
cout << cc.a << endl;
}
int main()
{
cout << "主线程id:" << this_thread::get_id() << endl;
CA ca();
thread mythreadObj(MyThread,ca);
mythreadObj.join();
system("pause");
return ;
}
三、std::ref()
上述代码运行可知,如果向子线程传入一个对象,会调用拷贝构造函数,这时用detach()是安全的,但是如果想要通过子线程来修改主线程对象的数据是不允许的,可以把18行的const去掉试试,是会报错的,那么可以用std::ref()来使这个对象得以修改。(当然,18行处也可以改成void MyThread(CA cc),这样也是可以修改,但是修改的只是拷贝的对象,对主线程的对象没有影响,而且会调用两次拷贝构造函数,浪费内存)
#include <iostream>
#include <string>
#include <thread>
using namespace std;
class CA
{
public:
int a;
CA(int m) :a(m)
{
cout << "构造函数执行 " << endl;
}
CA(const CA&m) :a(m.a)
{
cout << "拷贝构造函数执行 " << endl;
}
};
void MyThread(CA& cc)
{
cc.a++;
cout << "子线程id:" << this_thread::get_id() << endl;
cout << "my_thread " <<"ca.a:" << cc.a << endl;
}
int main()
{
cout << "主线程id:" << this_thread::get_id() << endl;
CA ca();
thread mythreadObj(MyThread, ref(ca));
cout << "main_thread " << "ca.a:" << ca.a << endl;
mythreadObj.join();
system("pause");
return ;
}
由结果可知,并不会调用拷贝构造函数,在子线程中操作的是主线程中的对象。这时需要注意了,如果用detach(),就不安全了。还是那个问题,对已经释放的变量进行非法操作必定带来隐患。
最新文章
- Storm Windowing storm滑动窗口简介
- [erl] erlang 进程注册和注销
- Android中的DrawerLayout
- 调用pyxmpp库PyQt编程打包成exe文件出错
- C语言宏定义时#(井号)和##(双井号)的用法1
- thinkphp分页样式
- PHP 高效分布代码转的
- [原创]自定义view之:快速开发一款Material Design风格的dialog的开源项目MDDialog
- PAT (Basic Level) Practise:1007. 素数对猜想
- shell sort
- O - 覆盖的面积 - hdu 1255(求面积)
- erlang学习笔记(1)
- 为什么要在onNewIntent的时候要显示的去调用setIntent
- js架构设计模式——MVVM模式下,ViewModel和View,Model有什么区别
- Nginx简介与安装
- kubernetes进阶(05)kubernetes的命令
- android TextView描边
- vim-go 安装
- 清空Sql server日志
- win10更新后,可以远程桌面ping也没问题,但是无法访问共享文件夹的解决方法
热门文章
- centos 6和centos7关闭防火墙的方法
- Example Bookstore schema showing how data is sharded DATABASE SHARDING
- http1.1管线话 vs htttp2.0 多路复用
- 2017年内容营销如何提高ROI转化率
- matplotlib展现混淆矩阵
- Ubuntu16.04源
- netcore kafka操作
- 七十九:flask.Restful之flask-Restful标准化返回参数示例
- 六十六:CSRF攻击与防御之CSRF防御之ajax防御和ajax封装
- nginx主配置文件实例