网站后台地址修改,中国电信收购腾讯,网站服务器租赁需要什么手续,超酷个人网站欣赏C11并发与多线程笔记#xff08;3#xff09;线程传参详解#xff0c;detach 大坑#xff0c;成员函数做线程函数 1、传递临时对象作为线程参数1.1 要避免的陷阱11.2 要避免的陷阱21.3 总结 2、临时对象作为线程参数2.1 线程id概念2.2 临时对象构造时机抓捕 3、传递类对象… C11并发与多线程笔记3线程传参详解detach 大坑成员函数做线程函数 1、传递临时对象作为线程参数1.1 要避免的陷阱11.2 要避免的陷阱21.3 总结 2、临时对象作为线程参数2.1 线程id概念2.2 临时对象构造时机抓捕 3、传递类对象、智能指针作为线程参数3.1 类对象作为线程参数3.2 智能指针作为线程参数 4、用成员函数指针做线程函数 1、传递临时对象作为线程参数
1.1 要避免的陷阱1
#include iostream
#include thread
using namespace std;void myPrint(const int i, char* pmybuf)
{//如果线程从主线程detach了//i不是mvar真正的引用实际上值传递即使主线程运行完毕了子线程用i仍然是安全的但仍不推荐传递引用//推荐改为const int icout i endl;//pmybuf还是指向原来的字符串所以这么写是不安全的cout pmybuf endl;
}int main()
{int mvar 1;int mvary mvar;char mybuf[] this is a test;thread myThread(myPrint, mvar, mybuf);//第一个参数是函数名后两个参数是函数的参数myThread.join();//myThread.detach();cout Hello World! endl;
}
在使用detach时不推荐引用传递指针传递肯定有问题
1.2 要避免的陷阱2
#include iostream
#include thread
#include string
using namespace std;void myPrint(const int i, const string pmybuf)
{cout i endl;cout pmybuf endl;
}int main()
{int mvar 1;int mvary mvar;char mybuf[] this is a test;//如果detach了这样仍然是不安全的//因为存在主线程运行完了mybuf被回收了系统采用mybuf隐式类型转换成string//推荐先创建一个临时对象thread myThread(myPrint, mvar, string(mybuf));就绝对安全了thread myThread01(myPrint, mvar, mybuf);//myThread01.join();myThread01.detach();cout I love China! endl;
}
在创建线程的同时构造临时对象的方法传递参数是可行的
1.3 总结
如果传递int这种基本数据类型推荐使用值传递不要用引用如果传递类对象避免使用隐式类型转换全部都是创建线程这一行就创建出临时对象然后在函数参数里用引用来接否则还会创建出一个对象终极结论建议不使用detach只使用join这样就不存在局部变量失效导致线程对内存的非法引用问题。
2、临时对象作为线程参数
2.1 线程id概念
id是个数字每个线程不管是主线程还是子线程实际上都对应着一个数字而且每个线程对应的这个数字都不一样。线程id可以用C标准库里的函数来获取。**std::this_thread::get_id()**来获取
2.2 临时对象构造时机抓捕
#includeiostream
#includethread
using namespace std;
class A {
public:int m_a;A(int a) :m_a(a) {cout A(int a):m_a(a)构造函数执行 this 线程id为 this_thread::get_id endl;}A(const A a):m_a(a.m_a){cout A(const A a):m_a(a.m_a)拷贝构造函数执行 this 线程id为 this_thread::get_id endl;}~A() {cout ~A() 析构函数执行 this 线程id为 this_thread::get_id endl;}};
void myPrint(const int i, const A pmybuf) {cout i endl;cout pmybuf.m_a endl;
}
int main() {int mvar 1;int myseconder 12;cout主线程id为 this_thread::get_id() endl;thread myThread01(myPrint, mvar, A(myseconder));myThread01.detach();cout hello world endl;
}3、传递类对象、智能指针作为线程参数
3.1 类对象作为线程参数
#include iostream
#include thread
using namespace std;class A {
public:mutable int m_i; //m_i即使实在const中也可以被修改A(int i) :m_i(i) {}
};void myPrint(const A pmybuf)//虽然是参数引用但还是没有修改主线程中m_i值
{pmybuf.m_i 199;//修改的值不影响main函数cout 子线程myPrint的参数地址是 pmybuf thread std::this_thread::get_id() endl;
}int main()
{A myObj(10);//myPrint(const A pmybuf)中引用不能去掉如果去掉会多创建一个对象//const也不能去掉去掉会出错//即使是传递的const引用但在子线程中还是会调用拷贝构造函数构造一个新的对象//所以在子线程中修改m_i的值不会影响到主线程//如果希望子线程中修改m_i的值影响到主线程可以用thread myThread(myPrint, std::ref(myObj));省去了传递时的拷贝构造函数//这样const就是真的引用了myPrint定义中的const就可以去掉了类A定义中的mutable也可以去掉了thread myThread(myPrint, myObj);myThread.join();//myThread.detach();cout Hello World! endl;
}
分析
void myPrint(const A pmybuf)//虽然是参数引用( pmybuf)但还是没有修改主线程中m_i值如果希望子线程中修改m_i的值影响到主线程可以用thread myThread(myPrint, std::ref(myObj));
3.2 智能指针作为线程参数
#include iostream
#include thread
#include memory
using namespace std;void myPrint(unique_ptrint ptn)
{cout thread std::this_thread::get_id() endl;
}int main()
{unique_ptrint myp(new int(10));//独占式智能指针只能通过std::move()才可以传递给另一个指针//传递后up就指向空新的ptn指向原来的内存//所以这时就不能用detach了因为如果主线程先执行完ptn指向的对象就被释放了thread myThread(myPrint, std::move(myp));myThread.join();//myThread.detach();return 0;
}
分析
unique_ptr 构造函数已经将拷贝函数和拷贝赋值删除了禁止拷贝如果需要将unique_ptr对象传入需要使用std::movemyp)
4、用成员函数指针做线程函数
class A {
public:int m_a;A(int a) :m_a(a) {cout A(int a):m_a(a)构造函数执行 this 线程id为 this_thread::get_id endl;}A(const A a):m_a(a.m_a){cout A(const A a):m_a(a.m_a)拷贝构造函数执行 this 线程id为 this_thread::get_id endl;}~A() {cout ~A() 析构函数执行 this 线程id为 this_thread::get_id endl;}void thread_work(int i) {cout 子线程thread_work执行 this thread_work线程id为 this_thread::get_id endl;}void operator()(int i){cout 子线程operator()执行 this operator()线程id为 this_thread::get_id endl;}
};int main() {cout主线程id为 this_thread::get_id() endl;A myobj(10);//生成一个类对象//参数1传成员函数地址//参数2对象名//参数3函数所需的参数thread myThread(A::thread_work,myobj,15)// myobjstd::ref(myobj) 不调用拷贝构造函数了那后续如果调用myThread就不安全了//thread myThread(myobj,15) //使用 operator()作为子线程入口myThread.detach();cout hello world endl;
}