C++线程的参数传递:值传递和引用

前言

线程一般通过复制或引用获取其数据。
默认情况下,您应该用一个副本。
为啥呢?如果您的线程通过引用获取其数据,那得非常小心参数的生命周期。


线程参数

线程是可变参数模板。所以它可以获得任意数量的参数。
现在咱们来看看通过复制或引用获取参数之间的区别:

    std::string s{ "C++11" }

    std::thread t([=] 
    { 
        std::cout << s << std::endl; 
    });
    t.join();

    std::thread t2([&] 
    { 
        std::cout << s << std::endl; 
    });
    t2.detach();

准确地说,在这个例子中,获取参数的不是线程,而是lambda函数。
因此第一个线程t1获取的是副本的数据([=]),第二个线程t2通过引用([&])获取其数据。
其中隐藏着什么危险?
线程t2通过引用获取其字符串s后就从其创建者的生命周期中分离了。
一方面,字符串的生命周期绑定到调用上下文的生命周期;另一方面,全局对象std::cout的生命周期绑定了主线程的生命周期。
因此,可能会发生字符串s的生命周期或std::cout的生命周期还没线程t2的生命周期长。现在我们处于未定义行为的坑中。。。。。。。。


你还不信?那咱们瞅瞅未定义的行为可能是什么样子:

// threadArguments.cpp

#include <chrono>
#include <iostream>
#include <thread>

class Sleeper {
public:
    Sleeper(int& i_) 
        :i{ i_ }
    {};

    void operator() (int k) 
    {
        for (unsigned int j = 0; j <= 5; ++j) 
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            i += k;
        }
        std::cout << std::this_thread::get_id() << std::endl;
    }
private:
    int& i;
};

int main() 
{
    std::cout << std::endl;

    int valSleeper = 1000;
    std::thread t(Sleeper(valSleeper), 5);
    t.detach();
    std::cout << "valSleeper = " << valSleeper << std::endl;

    std::cout << std::endl;
}

首先,valSleeper算是main中的一个全局变量。
Sleeper是个函数对象以及变量成员变量值为valSleeper和还有(int k)传入数字5。
关键的问题是,线程是通过引用得到valSleeper,并将其从主线程的生命周期中分离出来。然后它将执行函数对象的调用操作符()。
在该方法中,它从0到5计数,在每次迭代中休眠100毫秒并且将i+=k。
最后,它在屏幕上打印其id。
理论上运行完之后,结果必须是1000 + 6 * 5 = 1030。
但是,发生了什么?有些事情是完全错误的!!
这里写图片描述
有两个问题:其一,valSleeper是1000,其二,控制台上没有ID。
所以,这就是未定义的行为。原因在于子线程执行计算或将其id打印在std ::cout之前,主线程的生命周期结束。
如果主线程通过t.join()等待,直到这个子线程完成它的工作,我们得到预期的结果:

int main() 
{
    std::cout << std::endl;

    int valSleeper = 1000;
    std::thread t(Sleeper(valSleeper), 5);
    t.join();
    std::cout << "valSleeper = " << valSleeper << std::endl;

    std::cout << std::endl;
}

这里写图片描述


原文地址:

http://www.modernescpp.com/index.php/data-for-threads

猜你喜欢

转载自blog.csdn.net/y396397735/article/details/80994965
今日推荐