线程传参详解

一、传递临时对象作为线程参数

  1. 只要使用临时构造的A类对象作为参数传递给线程,那么就一定能够再主线程执行完毕前把线程函数的第二个参数构造出来,从而确保即使detach,线程也能安全运行
  2. 若传递int这种简单类型参数,建议都是值传递,不要用引用,绝对不能用指针。防止节外生枝。
  3. 如果传递类对象,避免隐式转换。全部都在创建线程这一行就构建出临时对象,然后在函数里,用引用来接,否则会造成浪费。(用引用会构造两次,不用引用会构造三次)
  4. 即便用引用,编译器也默认用copy方式,除非显式地告诉编译器

建议不适用detach(),只是用join(),这样就不存在局部变量失效导致线程对内存的非法引用问题。

二、临时参数作为线程参数继续讲

  1. 线程id概念
    每个线程实际上都对应一个数字,可以用std::thread::get_id()获取
  2. 临时对象构造时机捕捉
#include 
#include 
#include 
using namespace std;

class A {
public:
    A(int n) : m_number(n){
        cout << "constructor, address = " << this << ", thread id = " << std::this_thread::get_id() << endl;
    }
    A(const A& a) {
        cout << "copy constructor, address = " << this << ", thread id = " << std::this_thread::get_id() << endl;
    }
    ~A() {
        cout << "deconstructor" << endl;
    }
private:
    int m_number;
};

void myprint(const A &pa) {//用引用接收,copy 构造函数依然会执行,但是如果不用引用,会调用两次拷贝构造函数
                           //并且第二次拷贝是由子线程完成,可能会存在问题,故建议使用以用接收
    cout << "child thread address = " << &pa << ", child thread id = " << std::this_thread::get_id() << endl;
}

int main() {
    cout << "main thread id = " << std::this_thread::get_id() << endl;
    int n = 8;
    //thread mythread(myprint, n); //隐式转换
    thread mythread(myprint, A(n)); //临时对象,子线程函数的参数都在主线程中构造
    
    //mythread.join(); //阻塞主线程
    mythread.detach(); //主线程和子线程分离
    
    cout << "主线程结束!" << endl;
    
    return 0;
}
传递临时对象,临时对象的构造时机

三、传递类对象、智能指针作为线程参数

  1. 如果要传递类对象引用,std::ref()显式地告诉编译器,传一个引用到子线程中去
#include 
#include 
#include 
using namespace std;

class A {
public:
    A(int n) : m_number(n){
        cout << "constructor, address = " << this << ", thread id = " << std::this_thread::get_id() << endl;
    }
    A(const A& a) {
        cout << "copy constructor, address = " << this << ", thread id = " << std::this_thread::get_id() << endl;
    }
    ~A() {
        cout << "deconstructor" << endl;
    }
private:
    int m_number;
};

void myprint(const A &pa) {//用引用接收,copy 构造函数依然会执行,但是如果不用引用,会调用两次拷贝构造函数
                           //并且第二次拷贝是由子线程完成,可能会存在问题,故建议使用引用接收
    cout << "child thread address = " << &pa << ", child thread id = " << std::this_thread::get_id() << endl;
    //cout<< "the m_number of pa in child thread is "<
传递类对象
  1. 传递智能指针,std::move()
#include 
#include 
#include 
using namespace std;

void myprint2(unique_ptr p) {
    cout << "child thread ptr address is " << p << ", child thread id = " << std::this_thread::get_id() << endl;
}

int main() {
    cout << "main thread id = " << std::this_thread::get_id() << endl;

    unique_ptr myp(new int(100));
    cout << "main thread ptr address is " << myp << endl;
    thread mythread(myprint2, std::move(myp)); //智能指针
    mythread.join(); //用指针,只能用join()

    cout << "主线程结束!" << endl;
    
    return 0;
}
image.png

四、用成员函数指针做线程参数

#include 
#include 
#include 
using namespace std;

class A {
public:
    A(int n) : m_number(n){
        cout << "constructor, address = " << this << ", thread id = " << std::this_thread::get_id() << endl;
    }
    A(const A& a) {
        cout << "copy constructor, address = " << this << ", thread id = " << std::this_thread::get_id() << endl;
    }
    ~A() {
        cout << "deconstructor" << endl;
    }
    void print(int num) {
        cout << "child thread address is " << this << ", child thread id = " << std::this_thread::get_id() << endl;
    }
private:
    int m_number;
};

void myprint(const A &pa) {//用引用接收,copy 构造函数依然会执行,但是如果不用引用,会调用两次拷贝构造函数
                           //并且第二次拷贝是由子线程完成,可能会存在问题,故建议使用引用接收
    cout << "child thread address = " << &pa << ", child thread id = " << std::this_thread::get_id() << endl;
    //cout<< "the m_number of pa in child thread is "<
image.png

你可能感兴趣的:(线程传参详解)