《c++新经典》C++11并发与多线程笔记(9)

在这里插入图片描述

一、std::async / std::future创建后台任务并返回值

  • 希望线程返回一个结果
  • std::async 是个函数模板,用来启动一个异步任务,启动一个异步任务之后,返回一个std::future对象,std::future是一个类模板

什么叫“启动一个异步任务”

  • 就是自动创建一个线程并开始执行对应的入口函数,它返回一个std::future对象
  • 这个std::future对象里面就含有函数返回的结果(线程返回的结果),我们可以通过调用future对象的成员函数get()来获取结果
  • 有人也称呼std::future提供了一种访问异步操作结果的机制,就是说这个结果你可能没有办法马上拿到,但不久的将来,你就能够拿到结果了,所以大家都这么理解:这个future(对象)里会保存一个值
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;


int MyThread()
{
	std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
	std::chrono::milliseconds dura(5000);
	std::this_thread::sleep_for(dura);
	std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
	return 5;
}

int main(int argc, char* argv[])
{
	//下列程序通过std::future对象的get()成员函数,等待线程MyThread执行结束并返回结果
	//这个get()函数很牛,不拿到将来的返回值 誓不罢休,不拿到值我就卡在这里等待拿值
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
	//创建一个线程,并开始执行,绑定关系
	//流程并不会卡在这里
	std::future<int> result = std::async(MyThread);
	std::cout << "continue....." << std::endl;
	std::cout << result.get() << std::endl;//卡在这里等待MyThread执行完毕,拿到结果
	//get()只能调用一次,不能调用多次,否则会报异常
	//result.wait()  //等待线程返回,本身并不返回结果
	std::cout << "main end thread_id = " << std::this_thread::get_id() << std::endl;
	system("pause");
	return 0;
}

1.1类中调用线程入口函数

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;


class A
{
public:
	int MyThread(int my_par)
	{
		std::cout << "my_par = " << my_par << std::endl;
		std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
		std::chrono::milliseconds dura(5000);
		std::this_thread::sleep_for(dura);
		std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
		return 5;
	}
protected:
private:
};


int main(int argc, char* argv[])
{
	//下列程序通过std::future对象的get()成员函数,等待线程MyThread执行结束并返回结果
	//这个get()函数很牛,不拿到将来的返回值 誓不罢休,不拿到值我就卡在这里等待拿值	
	A my_obj_a;
	int tmp_par = 12;
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
	//第2个参数是对象引用,才能保证线程里用的是同一个对象
	std::future<int> result = std::async(&A::MyThread, &my_obj_a, tmp_par);
	std::cout << "continue....." << std::endl;
	std::cout << result.get() << std::endl;//卡在这里等待MyThread执行完毕,拿到结果
	//get()只能调用一次,不能调用多次,否则会报异常
	//result.wait()  //等待线程返回,本身并不返回结果
	std::cout << "main end thread_id = " << std::this_thread::get_id() << std::endl;
	system("pause");
	return 0;
}

1.2 std::async()传入参数

1.2.1 std::launch::async(),在调用的时候就开始创建线程

async()函数,默认用的就是std::launch::async | std::launch::thread标记

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;


class A
{
public:
	int MyThread(int my_par)
	{
		std::cout << "my_par = " << my_par << std::endl;
		std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
		std::chrono::milliseconds dura(5000);
		std::this_thread::sleep_for(dura);
		std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
		return 5;
	}
protected:
private:
};


int main(int argc, char* argv[])
{
	//下列程序通过std::future对象的get()成员函数,等待线程MyThread执行结束并返回结果
	//这个get()函数很牛,不拿到将来的返回值 誓不罢休,不拿到值我就卡在这里等待拿值

	
	A my_obj_a;
	int tmp_par = 12;
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
	//第2个参数是对象引用,才能保证线程里用的是同一个对象
	//std::future<int> result = std::async(&A::MyThread, &my_obj_a, tmp_par);


	std::future<int> result = std::async(std::launch::async, &A::MyThread, &my_obj_a, tmp_par);

	std::cout << "continue....." << std::endl;
	std::cout << result.get() << std::endl;//卡在这里等待MyThread执行完毕,拿到结果
	//get()只能调用一次,不能调用多次,否则会报异常
	//result.wait()  //等待线程返回,本身并不返回结果
	std::cout << "main end thread_id = " << std::this_thread::get_id() << std::endl;
	system("pause");
	return 0;
}

1.2.2 std::launch::defered

表示线程入口函数调用延迟到std::future的wait()或者get()函数调用时才执行

如果wait()或者get()函数没有被调用,那么线程实际上根本没有被创建
std::launch::defered延迟调用,并且没有创建新线程,是在主线程中调用的线程入口函数

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;


class A
{
public:
	int MyThread(int my_par)
	{
		std::cout << "my_par = " << my_par << std::endl;
		std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
		std::chrono::milliseconds dura(5000);
		std::this_thread::sleep_for(dura);
		std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
		return 5;
	}
protected:
private:
};


int main(int argc, char* argv[])
{
	//下列程序通过std::future对象的get()成员函数,等待线程MyThread执行结束并返回结果
	//这个get()函数很牛,不拿到将来的返回值 誓不罢休,不拿到值我就卡在这里等待拿值

	
	A my_obj_a;
	int tmp_par = 12;
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;

	std::future<int> result = std::async(std::launch::deferred, &A::MyThread, &my_obj_a, tmp_par);

	std::cout << "continue....." << std::endl;
	std::cout << result.get() << std::endl;//卡在这里等待MyThread执行完毕,拿到结果
	//get()只能调用一次,不能调用多次,否则会报异常
	//result.wait()  //等待线程返回,本身并不返回结果
	std::cout << "main end thread_id = " << std::this_thread::get_id() << std::endl;
	system("pause");
	return 0;
}

二、std::packged_task 打包任务,把任务打包起来

是个类模板,它的模板参数是各种可调用对象,通过std::packged_task 来把各种可调用对象包装起来,方便将来作为线程入口函数

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;


int MyThread(int my_par)
{
	std::cout << "my_par = " << my_par << std::endl;
	std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
	std::chrono::milliseconds dura(5000);
	std::this_thread::sleep_for(dura);
	std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
	return 5;
}

int main(int argc, char* argv[])
{
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
	std::packaged_task<int(int)> mypt(MyThread);//把MyThrea()函数通过packge_task包装起来
	std::thread t1(std::ref(mypt), 1); //线程直接开始执行,第2个参数 作为线程入口函数的参数
	t1.join();
	//std::future对象里包含有线程入口函数的返回结果,这里result保存MyThread的返回值
	std::future<int> result = mypt.get_future();
	std::cout << result.get() << std::endl;
	std::cout << "I love China" << std::endl;
	system("pause");
	return 0;
}

包装一个lambda表达式

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;


int main(int argc, char* argv[])
{
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
	//packaged_task包装起来的可调用对象还可以直接调用,所以从这个角度来讲,packaged_task对象也是一个可调用对象
	std::packaged_task<int(int)> mypt([](int my_par){
		std::cout << "my_par = " << my_par << std::endl;
		std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
		std::chrono::milliseconds dura(5000);
		std::this_thread::sleep_for(dura);
		std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
		return 5;
	});

	std::thread t1(std::ref(mypt), 1); //线程直接开始执行,第2个参数 作为线程入口函数的参数
	t1.join();
	//std::future对象里包含有线程入口函数的返回结果,这里result保存MyThread的返回值
	std::future<int> result = mypt.get_future();
	std::cout << result.get() << std::endl;
	std::cout << "I love China" << std::endl;
	system("pause");
	return 0;
}```

直接调用,相当于函数调用     

```cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;


int main(int argc, char* argv[])
{
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
	//packaged_task包装起来的可调用对象还可以直接调用,所以从这个角度来讲,packaged_task对象也是一个可调用对象
	std::packaged_task<int(int)> mypt([](int my_par){
		std::cout << "my_par = " << my_par << std::endl;
		std::cout << "MyThread Start thread_id = " << std::this_thread::get_id() << std::endl;
		std::chrono::milliseconds dura(5000);
		std::this_thread::sleep_for(dura);
		std::cout << "MyThread End thread_id = " << std::this_thread::get_id() << std::endl;
		return 5;
	});

	mypt(105);//直接调用,相当于函数调用
	std::future<int> result = mypt.get_future();
	std::cout << result.get() << std::endl;

	system("pause");
	return 0;
}

三、std::promise 类模板

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;

void MyThread(std::promise<int> &tmpp, int calc)
{
	//做一系列复杂的动作
	calc++;
	calc *= 10;
	//做其他运算,比如整整花费了5秒钟
	std::chrono::milliseconds dura(5000);
	std::this_thread::sleep_for(dura);

	//终于计算出来结果了
	int result = calc;
	tmpp.set_value(result);//结果保存在tmpp这个对象中
	return;
}

int main(int argc, char* argv[])
{
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
	//通过promise保存一个值,在将来某个时刻我们通过把一个future绑定到这个promise上来得到这个绑定的值

	std::promise<int> my_prom;//声明一个std::promise对象,保存的值类型为int
	std::thread t1(MyThread, std::ref(my_prom), 180);
	t1.join();

	//获取结果值
	std::future<int> fu1 = my_prom.get_future();//promise和future绑定,用于获取线程返回值
	auto result = fu1.get();
	std::cout << "result = " << result << std::endl;
	std::cout << "I Love China!" << std::endl;
	system("pause");
	return 0;
}

两个线程

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
#include <future>
using namespace std;

void MyThread(std::promise<int> &tmpp, int calc)
{
	//做一系列复杂的动作
	calc++;
	calc *= 10;
	//做其他运算,比如整整花费了5秒钟
	std::chrono::milliseconds dura(5000);
	std::this_thread::sleep_for(dura);

	//终于计算出来结果了
	int result = calc;
	tmpp.set_value(result);//结果保存在tmpp这个对象中
	return;
}

void MyThread2(std::future<int> &tmpf)
{
	auto result = tmpf.get();
	std::cout << "MyThread2 result = " << result << std::endl;
	return;
}

int main(int argc, char* argv[])
{
	std::cout << "main thread_id = " << std::this_thread::get_id() << std::endl;
	//通过promise保存一个值,在将来某个时刻我们通过把一个future绑定到这个promise上来得到这个绑定的值

	std::promise<int> my_prom;//声明一个std::promise对象,保存的值类型为int
	std::thread t1(MyThread, std::ref(my_prom), 180);
	t1.join();

	//获取结果值
	std::future<int> fu1 = my_prom.get_future();//promise和future绑定,用于获取线程返回值
	
	std::thread t2(MyThread2, std::ref(fu1));
	t2.join();//等待MyThread2线程执行完毕
	std::cout << "I Love China!" << std::endl;
	system("pause");
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值