目录
一.传入普通函数指针作为线程函数时
二.传入函数对象作为线程函数时
1.模板类
2.模板函数
三.传入匿名函数作为线程函数时
简单认识std::thread()
当我们做并发工作时,需要使用std::thread()来用于创建、管理和同步线程。首先,我们要知道std::thread()的参数列表构成
第一个参数:可作为线程函数的三种形式
函数指针
函数对象(operator()()重载函数,也叫仿函数)——重难点
Lambda匿名表达式。
其他参数:相当于可变参数列表,根据调用函数的参数列表来传入实参
这里我们主要讲解传入线程函数时的注意事项及实现方式
尤其注意:
如果你想传递引用,一定要调用std::ref()把传入地址转成引用,下面的代码中有介绍
定义形式:std::thread first(函数名,参数列表);
#include
#include
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(类名
(),参数列表); 2.std::thread second(&类名
::operator(),&对象名 ,参数列表); 函数模板下的operator作为thread形参的写法
3.std::thread third(类名(), 参数列表); ——这里竟然隐式调用operator,目前我不理解
4.std::thread fourth(&类名::operator()
,&对象名, 参数列表); 下面将给出具体调用,并采用值传递
#include
#include
using namespace std;
template //函数模板
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); //值传递
//2.创建对象,调用operator
mythread obj;
std::thread first(&mythread::operator(),&obj ,number);
first.join();
//不使用线程时
//1.mythread()(number);
//2.mythread obj;
// obj.operator()()
return 0;
}
#include
#include
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 //函数模板
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(),&obj, number); //值传递
first.join();
//不使用线程时
//1.mythread()(number);
/*2.obj(number);
或者
obj.operator()(number);
*/
return 0;
}
std::thread first(&mythread::operator()
,&obj, number); 这段代码很重要在上面的例子中,`Mythread`是一个类对象,它重载了函数模板`operator()()`。`std::thread`的构造函数的第一个参数是一个指向成员函数的指针,这里使用了`&Mythread::operator()
`来指定`operator() `函数作为线程函数。第二个参数是一个指向类对象的指针,这里使用了`&obj`来指定`obj`作为类对象。最后,`number`是传递给`operator() `函数的参数。 需要注意的是,如果类对象的成员函数是一个非静态成员函数,那么需要将类对象的指针作为第二个参数传递给`std::thread`的构造函数。如果成员函数是一个静态成员函数,那么可以将类名作为第一个参数传递给`std::thread`的构造函数。(运算符重载函数不能是静态函数)
定义格式:std::thread first(匿名函数体,匿名函数里的参数列表);
#include
#include
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;
}