C++ thread线程函数传参原理剖析

知识的学习在于点滴记录,坚持不懈;知识的学习要有深度和广度,不能只流于表面,坐井观天;知识要善于总结,不仅能够理解,更知道如何表达!

thread线程函数参数问题


从C++11开始,终于提供了语言级别的thread类库,从此可以通过C++语言编写多线程程序,做到一次编写,到处编译。thread对象可以传递普通函数、函数对象、lambda表达式等作为线程函数,使用起来非常方便。最近看到有人(tony)提出这样一个问题,代码片段:

#include <iostream>
#include <thread>

void handler1(int b)  // 此处形参b,接收t1实参a的值,正确!!!
{
   
    std::cout << "do handler1" << std::endl;
}
void handler2(int &b)  // 此处形参b,想引用实参a,语法错误!!!为什么???
{
   
    std::cout << "do handler2" << std::endl;
}
int main()
{
   
    int a = 10;
    std::thread t1(handler1, a);
    t1.join();

    // std::thread t2(handler2, a);   这里编译错误!!!
    // t2.join();
}

tony定义了一个thread对象,绑定了handler2线程函数,handler2的参数是一个普通的左值引用变量int &b,为什么不能接收实参a? 也就是std::thread t2(handler2, a); 这句代码直接编译错误,在visual studio 2019上(编译默认使用C++ 14标准)错误信息如下:
在这里插入图片描述
可以看到vs报错“invoke未找到匹配的重载函数”,具体原理后面给大家详细解释。如果线程函数非得用int &b这样的左值引用来接收,使用的时候如下即可:

#include <iostream>
#include <thread>

void handler1(int b)
{
   
    std::cout << "do handler1" << std::endl;
}
void handler2(int &b)
{
   
    std::cout << "do handler2" << std::endl;
}
int main()
{
   
    int a = 10;
    std::thread t1(handler1, a);
    t1.join();

    std::thread t2(handler2, std::ref(a));  //  注意这里使用std::ref(a)即可!!!
    t2.join();
}

tony的问题就是,他写的线程函数handler2,形参是int &b,为什么不能直接接收实参变量a,但是用std::ref(a)又可以了,底层原理是什么?

学习下thread类的源码

要从原理上解释上面的问题,我们需要看看thread类的源码,主要看从定义一个thread对象,到线程函数的调用,中间都执行了哪些代码操作,通过查看源码,看看造成上面问题的根本原因是什么?

从VS2019的C++类库中看thread的源码

拷贝thread的源码,我们实现一个自己的线程类Slthread,如下:

#include <iostream>
#include <tuple>
using namespace std;

class Slthread
{
   
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值