2. C++使用Thread线程参数传递问题

1. 说明

在子线程函数中进行参数传递,实际上是Thread类的构造函数对传递的参数进行了拷贝,拷贝到线程独立的内存中,及时参数是引用的形式,也可以在新线程中进行访问,如果参数传递时的类型不一致,在线程的上下文中会对类型进行隐式类型转换。不过当传递的参数是指针类型时需要特别注意,可能会有问题,具体见下文。

2. 普通参数传递

如果在子线程中不需要对传递过来的参数进行更改操作,那么传递参数时正常传递就行,为避免误操作,可以使用const关键字进行修饰 :

#include 
using namespace std;

#include 

void myprint(const string s)
{
    cout << s << endl; 
}

int main()
{
    string s = "xiaoming";

    thread mythread(myprint, s);

    mythread.join();

    std::cout << "主线程:"<<s<<endl;

    return 0;
}

3. 传递引用(使用ref)

如果想在子线程中修改主线程中传递过来的数据,需要使用**std::ref()**函数:

#include 
using namespace std;

#include 

void myprint(string& s)
{
    
    s = "xiaohong......";
    cout <<"子线程:" << s << endl;
    
}

int main()
{
    string s = "xiaoming";

    thread mythread(myprint, ref(s));

    mythread.join();

    std::cout << "主线程:"<<s<<endl;

    return 0;
}

4. 传递指针变量

Thread类虽然会对参数类型进行转换,但是遇到指针变量,还是需要进行显式类型转换,否则会出现问题。
悬垂指针:当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称悬垂指针

#include 
using namespace std;

#include 

void myprint(const string& mbuffer)
{
    cout <<"子线程:" << mbuffer << endl;
}

int main()
{
    char buffer[] = "this is a test....";

    thread mythread(myprint,string(buffer));//使用string进行显式类型转换,避免悬垂指针

    mythread.join();

    std::cout << "主线程:运行结束...."<<endl;

    return 0;
}

4. 传递自定义的类

在自定义类中使用关键字mutable定义了一个变量,可以方便更改操作。实际将自定义类对象传输到子线程中,Thread构造函数会调用自定义类的拷贝构造函数,实际传输到子线程的类并非主线程中的原始类对象:

#include 
using namespace std;

#include 

class A
{
public:
    A(int a) :m_i(a)
    {
        cout << "[A::A(int a )构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    A(const A& a) :m_i(a.m_i)
    {
        cout << "[A::A(const a )拷贝构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    ~A()
    {
        cout << "[A::~A( )析构函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
public:
    mutable int m_i;
};

void myprint(const A& a)//这里虽然使用了引用&,但输出结果发现并非是真正的引用,实际上引用的是拷贝构造函数复制出来的另一份对象a
{
    a.m_i = 2;//对变量进行更改
    cout <<"子线程入口函数(类中的变量):" << a.m_i << endl;
}


int main()
{
    int mvar = 1;

    A a(mvar);

    thread mythread(myprint,a);

    mythread.join();

    cout << "主线程(类中的变量):" << a.m_i << endl;//输出原始类对象中的m_i变量

    std::cout << "主线程:运行结束...."<<endl;

    return 0;
}

运行结果如下:发现两次输出的m_i的变量值是不一样的,而且类A的拷贝构造函数执行了
2. C++使用Thread线程参数传递问题_第1张图片
若想做到对自定义类真正的引用,需要使用std::ref()函数
修改上述代码如下:

thread mythread(myprint,std::ref(a));//传递参数时使用 ref 函数才能做到整正的引用

此时再输出结果会发现:并未调用自定义类中的拷贝构造函数
2. C++使用Thread线程参数传递问题_第2张图片

5. 传递自定义的类成员函数

注意使用引用的方式进行参数传递

#include 
using namespace std;

#include 

class A
{
public:
    A(int a) :m_i(a)
    {
        cout << "[A::A(int a )构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    A(const A& a) :m_i(a.m_i)
    {
        cout << "[A::A(const a )拷贝构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    ~A()
    {
        cout << "[A::~A( )析构函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    //添加成员函数
    void thread_work(int num)
    {
        cout << "[成员函数thread_work执行了....]" << endl;
    }

public:
    mutable int m_i;
};

void myprint(const A& a)
{
    a.m_i = 2;//对变量进行更改
    cout <<"子线程入口函数(类中的变量):" << a.m_i << endl;
    
}


int main()
{
    int mvar = 1;

    A myobj(mvar);

    //第一个参数是成员函数名,第二个参数是类对象名(注意使用引用的方式),第三个参数是成员函数需要的参数
    thread mythread(&A::thread_work,&myobj,15);

    mythread.join();

    std::cout << "主线程:运行结束...."<<endl;

    return 0;
}

6. 传递智能指针(使用std::move()函数)

#include 
using namespace std;

#include 

void myprint(unique_ptr<int> pzn)
{
    
}

int main()
{
    unique_ptr<int> mypzn(new int(100));

    thread mythread(myprint,std::move(mypzn));

    mythread.join();

    std::cout << "主线程:运行结束...."<<endl;

    return 0;
}

你可能感兴趣的:(C++并发编程,c++,线程参数传递)