// 多线程7.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include <thread>
#include <list>
#include <mutex>
#include <future>
using namespace std;
class A
{
public:
int mythread(int myvar) //线程入口函数
{
cout << myvar<<endl;
cout << "mythread() start" << "thread id =" << this_thread::get_id() << endl; //打印线程id
chrono::milliseconds dura(3000);
this_thread::sleep_for(dura); //休息3s
cout << "mythread() end" << "thread id =" << this_thread::get_id() << endl; //打印线程id
return 5;
}
};
int mythread2(int myvar) //线程入口函数
{
cout << myvar << endl;
cout << "mythread() start" << "thread id =" << this_thread::get_id() << endl; //打印线程id
chrono::milliseconds dura(3000);
this_thread::sleep_for(dura); //休息3s
cout << "mythread() end" << "thread id =" << this_thread::get_id() << endl; //打印线程id
return 5;
}
void mythread3(std::promise<int> &temp, int calc) //注意第一个参数
{
//做一系列复杂的操作
calc++;
calc *= 10;
//做其他运算,比如整整花费了3s钟
chrono::milliseconds dura(3000);
this_thread::sleep_for(dura); //休息3s
//终于计算出结果
int result = calc;
temp.set_value(result); //结果保存到了temp这个对象中
return;
}
void mythread4(future<int> &tempf)
{
auto result = tempf.get();
cout << "mythread4 resule=" << result << endl;
return;
}
int main()
{
//一:std::async、std::future创建后台任务并返回值
//希望线程返回一个结果(除此之外,也可以通过全局变量、引用、指针等形式)
//std::async是一个函数模板,用来启动一个异步任务,启动异步任务之后,返回一个std::future对象,std::future是个类模板
//什么叫“启动一个异步任务”,就是自动创建一个线程并开始执行对应的线程入口函数,它返回一个future对象
//这个future对象里边就含有线程入口函数所返回的结果(也称线程返回的结果),我们可以通过调用future对象的成员函数get()来获取结果
//std::future提供了一种访问异步操作结果的机制,就是说这个结果可能没有办法马上拿到,但不久的将来(线程执行完毕的时候),才能拿到结果
//可以通过额外向async()传递一个参数,该参数类型是launch类型(枚举类型),来达到一些特殊的目的:
//a)std::launch::deferred: 表示线程入口函数调用被延迟到std::future对象的wait()或get()函数调用时才执行 (如果没有调用wait或get,则此线程不会被执行,实际上线程根本没被创建)
//std::launch::deferred:延迟调用,并且没有创建新线程,是在主线程中调用的线程入口函数
//b)std::launch::async:在调用async函数时就立即开始创建线程。
//c)async的默认参数为:launch::async | launch::deferred,由系统自行决定调用方式(同步:不创建新线程还是异步:创建新线程)
//下列程序通过future对象的get()成员函数等待线程执行结束并返回结果
//A myobja;
//int tempvar = 12;
//cout << "main " << "thread id =" << this_thread::get_id() << endl;
//future <int> result = async(std::launch::async, &A::mythread,&myobja,tempvar); //自动创建一个线程并开始执行对应的线程入口函数,返回一个future对象。流程不会卡在这里
//cout << "continue.....!" << endl;
//cout << "continue.....!" << endl;
//cout << "continue.....!" << endl;
//cout << "continue.....!" << endl;
//cout << "continue.....!" << endl;
//cout << "continue.....!" << endl;
//cout << "continue.....!" << endl;
//cout << result.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果。只能调用一次,调用多次会报异常
result.wait(); //等待线程返回,本身不返回结果
//cout << "主线程end" << endl;
//二:std::packaged_task:打包任务,把任务包装起来
//是个类模板,它的模板参数是各种可调用对象;通过std::packaged_task 来把各种可调用对象包装起来,方便将来作为线程入口函数来调用
//packaged_task包装起来的可调用对象还可以直接调用,所以从这个角度讲,packaged_task对象是个可调用对象 (如在与线程入口函数包装完后,直接mypt(tempvar),但不会创建子线程,是在主线程中执行)
//cout << "main " << "thread id =" << this_thread::get_id() << endl;
//packaged_task<int(int)> mypt(mythread2); //把函数mythread2通过packaged_task包装起来
/*
//lambda表达式
packaged_task<int(int)> mypt([](int myvar) {
cout << myvar << endl;
cout << "mythread() start" << "thread id =" << this_thread::get_id() << endl; //打印线程id
chrono::milliseconds dura(3000);
this_thread::sleep_for(dura); //休息3s
cout << "mythread() end" << "thread id =" << this_thread::get_id() << endl; //打印线程id
return 5;
});
*/
//int tempvar = 12;
//thread t1(ref(mypt),tempvar); //线程开始执行,tempvar为线程入口函数的参数
//t1.join(); //等待线程执行完毕
//future <int> result = mypt.get_future(); //future对象里包含有线程入口函数的返回结果,这里result保存mythread2返回结果
//cout << result.get() << endl;
//cout << "主线程end" << endl;
//三:std::promise,类模板
//我们能够在某个线程中给它赋值,然后我们可以再其他线程中,把这个值取出来
//总结:通过promise保存一个值,在将来某个时刻通过一个future绑定到这个promise上来得到这个绑定的值
promise <int> myprom; //声明一个promise对象myprom,保存值的类型为int
int tempvar = 12;
thread t1(mythread3, ref(myprom), tempvar);
t1.join(); //用了thread对象,就必须用join来等
//获取结果值
future<int>ful = myprom.get_future(); //promise与future绑定
//auto result = ful.get(); //get只能调用一次,不能调用多次
//cout << "result = " << result << endl;
//线程二获取结果
thread t2(mythread4, ref(ful));
t2.join();
cout << "主线程end" << endl;
//四:小结:到底怎么用,什么时候用
//学习这些的目的,并不是要把它们都用在实际开发中
//相反,如果能用最少的东西写出一个稳定高效的多线程程序,更值得赞赏
return 0;
}