std::thread的三种函数调用表示方法

目录

一.传入普通函数指针作为线程函数时

二.传入函数对象作为线程函数时

1.模板类

2.模板函数

 三.传入匿名函数作为线程函数时


简单认识std::thread()

当我们做并发工作时,需要使用std::thread()来用于创建、管理和同步线程。首先,我们要知道std::thread()的参数列表构成

        第一个参数:可作为线程函数的三种形式

                函数指针

                函数对象(operator()()重载函数,也叫仿函数)——重难点

                Lambda匿名表达式。

        其他参数:相当于可变参数列表,根据调用函数的参数列表来传入实参

这里我们主要讲解传入线程函数时的注意事项及实现方式

尤其注意: 

        如果你想传递引用,一定要调用std::ref()把传入地址转成引用,下面的代码中有介绍


一.传入普通函数指针作为线程函数时

定义形式:std::thread first(函数名,参数列表);

#include <iostream>
#include <thread>

using namespace std;
/*
    兄弟们好好研究研究char const*const& str这个,两个const分别起什么作用呢?
    记住口诀:左定量,右定向
    1. 第一个const:表示str是一个指向常量字符的指针,即指针所指向的字符内容不能被修改。

    2. 第二个const:表示str是一个常量引用,即在函数内部不能修改str的值。同时,使用常量引用可以避            
       免不必要的拷贝,提高代码效率。
*/
void test(char const*const& str) {//传入char*类型的引用
	cout << "正确使用std::ref()转换,test函数的p的地址 = "<< &str << " 传送的字符串 = " << str << endl;
}
void test1(char const*const& str) {
	cout << "没有使用std::ref()转换,test函数的p的地址 = " << &str << " 传送的字符串 = " << str <<  endl;
}

int main(int argc, char* argv[]) {
	char str[11] = "加油奥力给";
	char* p = str;
//下面都是关于p自身的地址,而不是str的字符串
	cout << "主函数的p地址 = "<< &p << endl;

/*
注意:
     如果想成功在thread()里传入引用,一定要遵循这两步,缺一不可
     第一步:std::ref()用于将一个对象(地址)包装成一个引用类型的对象

     第二步:当然了如果想传递引用,test参数列表也要声明取&,char* const& str,如果不声明这个&,那                
            std::ref()就失去了意义
*/

//使用std::ref()的情况
	std::thread first(test, std::ref(p));
	first.join();     //join()意味着先执行完子线程也就是test()后,再继续执行下面的部分。
//未使用std::ref()的情况
	std::thread second(test1, p);
	second.join();    //一定要选择好线程的执行方式,不然程序会抛出异常
	return 0;
}


二.传入函数对象作为线程函数时

定义格式:

        1.std::thread first(直接调用类+operator(),参数列表);

        2.std::thread first(&声明对象+operator(),&对象名, 参数列表);

类模板下的operator作为thread形参的写法

        1.std::thread first(类名<T>(),参数列表);

        2.std::thread second(&类名<T>::operator(),&对象名 ,参数列表); 

函数模板下的operator作为thread形参的写法

        3.std::thread third(类名(), 参数列表);  ——这里竟然隐式调用operator,目前我不理解

        4.std::thread fourth(&类名::operator()<T>,&对象名, 参数列表);

下面将给出具体调用,并采用值传递

1.模板类

#include <iostream>
#include <thread>

using namespace std;

template<typename T>    //函数模板
class mythread {
public:
	explicit mythread() {    //构造函数
		//cout << "default gaozao is use" << endl;
	}
	mythread(const mythread& p) {    //拷贝构造函数
		//cout << "copy thread" << " address = " << &p << endl;
	}
	~mythread() {    //析构函数

	}

	void operator()(T number){	    //仿函数
		cout<<number<<endl;
	}


private:

};

int main(int argc, char* argv[]) {
//接下来我们的目的就是将函数对象传入到thread当第一个参数,假设传入实参类型是int
    int number = 666;
//使用线程时
  //1.不创建对象,直接调用operator函数
    //std::thread first(mythread<int>(),number);    //值传递
  //2.创建对象,调用operator
    mythread<int> obj;
    std::thread first(&mythread<int>::operator(),&obj ,number); 

    first.join();

//不使用线程时
    //1.mythread<int>()(number);
	//2.mythread<int> obj;
    //  obj.operator()()
    return 0;
}

2.模板函数

#include <iostream>
#include <thread>

using namespace std;

class mythread {
public:
	explicit mythread() {    //构造函数
		//cout << "default gaozao is use" << endl;
	}
	mythread(const mythread& p) {    //拷贝构造函数
		//cout << "copy thread" << " address = " << &p << endl;
	}
	~mythread() {    //析构函数

	}
	template<typename T>    //函数模板
	void operator()(T number) {	    //仿函数
		cout << number << endl;
	}


private:

};

int main(int argc, char* argv[]) {
//接下来我们的目的就是将函数对象传入到thread当第一个参数,假设传入实参类型是int
	int number = 666;
//使用线程时
  //1.不创建对象,调用operator
    //std::thread first(mythread(), number);     //这里它竟然隐式调用operator,目前我不理解
  //2.创建对象,调用operator
	mythread obj;
	std::thread first(&mythread::operator()<int>,&obj, number);    //值传递

	first.join();

//不使用线程时
  //1.mythread()(number);
  /*2.obj(number);
    或者
	obj.operator()<int>(number);
  */

	return 0;
}

        std::thread first(&mythread::operator()<int>,&obj, number); 这段代码很重要

        在上面的例子中,`Mythread`是一个类对象,它重载了函数模板`operator()()`。`std::thread`的构造函数的第一个参数是一个指向成员函数的指针,这里使用了`&Mythread::operator()<int>`来指定`operator()<int>`函数作为线程函数。第二个参数是一个指向类对象的指针,这里使用了`&obj`来指定`obj`作为类对象。最后,`number`是传递给`operator()<int>`函数的参数。

        需要注意的是,如果类对象的成员函数是一个非静态成员函数,那么需要将类对象的指针作为第二个参数传递给`std::thread`的构造函数。如果成员函数是一个静态成员函数,那么可以将类名作为第一个参数传递给`std::thread`的构造函数。(运算符重载函数不能是静态函数)


 三.传入匿名函数作为线程函数时

定义格式:std::thread first(匿名函数体,匿名函数里的参数列表);

#include <iostream>
#include <thread>

using namespace std;

int main(int argc, char* argv[]) {
	int a = 44;
	cout << "main函数里的a的地址 = "<< & a << endl;

//这里很好玩,匿名函数有两种方式访问成员,最后效果相同,都实现了对a的引用
	
//1.thread(), 调用匿名函数后,再填入实参传递到匿名函数中
	std::thread t1([](int& a) {std::cout << "方法1里的a的地址 = " << &a << endl; }, std::ref(a));
	t1.join();
//2.通过控制[]的权限来直接访问成员,[]的具体权限可以查询百度更加全面了解
	std::thread t2([&]() {std::cout << "方法2里的a的地址 = " << &a << endl; });
	t2.join();
	
	return 0;
}

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值