C++多线程编程第三讲--线程传参详解,detach()大坑,成员函数做线程函数
/*线程传参详解,detach()大坑,成员函数做线程函数*/
//(1)传递临时对象作为线程参数
//(1.1)要避免的陷阱
#include<iostream>
#include<thread>
using namespace std;
void myprint(const int& i, const char* pmybuf)
{
cout << i << endl; //这个地方i的地址已经不是主线程中对应的地址了,也就是说虽然用的是引用传递的数据,
//但是实际上是把主线程中的数据在内存中又复制了一份传递到了这个线程中。
cout << pmybuf << endl; //这个地方用的数据的地址是与主线程中的数据的地址是相同的。
}
int main()
{
int myvar = 1;
int& mvary = myvar;
char mybuf[] = "ths is a test";
//虽然函数参数i接受的是一个引用,但实际到了线程内是复制了一份数据进的线程
//但是对应指针而言,是不会复制一份数据进入新的线程中的,所以这个地方用了detach,第二个参数
//用了指针,是存在错误的,一旦主线程中的mybuf被释放掉,而新线程中还在用这个数据,就会出现错误
thread mytobj(myprint, mvary, mybuf);
if (mytobj.joinable())
{
mytobj.detach();
}
cout << "I Love China!" << endl;
return 0;
}
// 修改如下:
#include<iostream>
#include<thread>
#include<string>
using namespace std;
void myprint(const int i, const string& pmybuf)
{
cout << i << endl;
cout << pmybuf.c_str() << endl;
}
int main()
{
int myvar = 1;
int& mvary = myvar;
char mybuf[] = "ths is a test";
//这个地方存在一个char *转成string的一个隐式转换,转换的过程在新的线程执行的,
//一旦主线程执行结束,这个过程还没有转换完成,新的线程中就接收不到数据,所以还是存在bug。
thread mytobj(myprint, mvary, mybuf);
if (mytobj.joinable())
{
mytobj.detach();
}
cout << "I Love China!" << endl;
return 0;
}
// 上面的程序依然还有bug
// 我们需要再次修改
#include<iostream>
#include<thread>
#include<string>
using namespace std;
void myprint(const int i, const string& pmybuf)
{
cout << i << endl;
cout << pmybuf.c_str() << endl;
}
int main()
{
int myvar = 1;
int& mvary = myvar;
char mybuf[] = "ths is a test";
thread mytobj(myprint, mvary, string(mybuf)); //这种临时string的写法可以保证在新线程中可以获得一个有效的的数据,
if (mytobj.joinable())
{
mytobj.detach();
}
cout << "I Love China!" << endl;
return 0;
}
// 此用法的验证
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
int m_i;
//带参构造函数
A(int a) :m_i(a)
{
cout << "[A::A(int a)构造函数执行]" << endl;
}
//拷贝构造函数
A(const A& a) :m_i(a.m_i)
{
cout << "[A::A(const A& a)拷贝构造函数执行]" << endl;
}
~A()
{
cout << "[A::~A()析构函数执行]" << endl;
}
};
void myprint(const int i, const A& pmybuf)
{
cout << &pmybuf << endl;
}
int main()
{
int myvar = 1;
int mysecondpar = 12;
//经过实验得出,由数字mysecondpar转换成A的对象调用构造函数是在新的线程中执行的
thread mytobj(myprint, myvar, mysecondpar);
if (mytobj.joinable())
{
mytobj.detach();
}
cout << "I Love China!" << endl;
return 0;
}
// 修改:
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
int m_i;
//带参构造函数
A(int a) :m_i(a)
{
cout << "[A::A(int a)构造函数执行]" << endl;
}
//拷贝构造函数
A(const A& a) :m_i(a.m_i)
{
cout << "[A::A(const A& a)拷贝构造函数执行]" << endl;
}
~A()
{
cout << "[A::~A()析构函数执行]" << endl;
}
};
void myprint(const int i, const A& pmybuf)
{
cout << &pmybuf << endl;
}
int main()
{
int myvar = 1;
int mysecondpar = 12;
//经过实验得出,这种临时转换会在主线程中执行,并且还会执行一份拷贝构造函数
thread mytobj(myprint, myvar, A(mysecondpar));
if (mytobj.joinable())
{
mytobj.detach();
}
cout << "I Love China!" << endl;
return 0;
}
//(1.2)总结
// 自定义的类型尽量用引用来接受,否则会出现多次复制的情况,降低程序性能。
//(2)临时对象作为线程参数继续讲
//(2.1)线程id的概念:每一个线程都对应一个id,std::this_thread::get_id()
//(3)传递类对象,智能指针作为线程参数
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
mutable int m_i;
//带参构造函数
A(int a) :m_i(a)
{
cout << "[A::A(int a)构造函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
//拷贝构造函数
A(const A& a) :m_i(a.m_i)
{
cout << "[A::A(const A& a)拷贝构造函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
~A()
{
cout << "[A::~A()析构函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
};
void myprint2(const A& pmybuf)
{
pmybuf.m_i = 199;
cout << "m_i = :" << pmybuf.m_i << " this_thread id = " << std::this_thread::get_id() << endl;
}
int main()
{
int i = 100;
A a(i);
//即便myprint2的参数是一个引用,且在新的线程中修改了m_i的值,但是主线程中a的m_i的值依然没有改变
thread mythread(myprint2, a);
mythread.join();
cout << a.m_i << endl;
cout << "main thread end" << endl;
return 0;
}
// 如果想要修改主线程中的a的数据,那么需要用到std::ref()
#include<iostream>
#include<thread>
#include<string>
using namespace std;
class A
{
public:
int m_i;
//带参构造函数
A(int a) :m_i(a)
{
cout << "[A::A(int a)构造函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
//拷贝构造函数
A(const A& a) :m_i(a.m_i)
{
cout << "[A::A(const A& a)拷贝构造函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
~A()
{
cout << "[A::~A()析构函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
};
void myprint2(A& pmybuf)
{
pmybuf.m_i = 199;
cout << "m_i = :" << pmybuf.m_i << " this_thread id = " << std::this_thread::get_id() << endl;
}
int main()
{
int i = 100;
A a(i);
//使用了ref函数,则新线程中值的修改也影响到了主线程的值
thread mythread(myprint2, std::ref(a));
mythread.join();
cout << a.m_i << endl;
cout << "main thread end" << endl;
return 0;
}
#include<iostream>
#include<thread>
#include<string>
#include<memory>
using namespace std;
void myprint2(unique_ptr<int> iptr)
{
cout << "iptr = :" << *iptr << " this_thread id = " << std::this_thread::get_id() << endl;
}
int main()
{
unique_ptr<int> iptr(new int(100));
thread mythread(myprint2, std::move(iptr));
mythread.join();
return 0;
}
//(4)用成员函数指针做线程函数
#include<iostream>
#include<thread>
#include<string>
#include<memory>
using namespace std;
class A
{
public:
int m_i;
//带参构造函数
A(int a) :m_i(a)
{
cout << "[A::A(int a)构造函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
//拷贝构造函数
A(const A& a) :m_i(a.m_i)
{
cout << "[A::A(const A& a)拷贝构造函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
~A()
{
cout << "[A::~A()析构函数执行] " << this << " thread_id = " << std::this_thread::get_id() << endl;
}
void thread_work(int num)
{
cout << "num = " << num << " thread id = " << std::this_thread::get_id() << endl;
}
void operator()(int num)
{
cout << "num = " << num << " thread id = " << std::this_thread::get_id() << endl;
}
};
int main()
{
int i = 100;
A a(i);
thread mytobj(&A::thread_work, a, i);
mytobj.join();
A a1(100);
thread mytobj2(a1, 10);
mytobj2.join();
return 0;
}
posted on 2021-09-26 21:16 xcxfury001 阅读(196) 评论(0) 收藏 举报
浙公网安备 33010602011771号