IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++线程三 -> 正文阅读

[C++知识库]c++线程三

std::async() 、 std::package_task<> 、std::promise<> 、std::future<>、 std::shared_future<>

一、async()可以看做package_task<>和promise<>的封装

他们的作用都是获取线程的返回值。

我们前面所用的线程函数都是void类型的,但其实线程可以有返回值,当然我们可以用全局变量记录线程处理结果。

1、async()函数是最简单的使用方式

int threadFunc(int m)
{
	cout << "threadFunc id:" << this_thread::get_id() << endl;
	this_thread::sleep_for(chrono::seconds(5));
	return ++m;

}
int main()
{
	cout << "main id:" << this_thread::get_id() << endl;
	int i = 1001;
	future<int> result = async(threadFunc, i);
	cout << result.get() << endl;  //get()会等待线程结束并获取返回值,同wait()只等待线程结束,返回类型void

	cout << "程序结束" << endl;

	return 0;
}

async(threadFunc, i);其实是async(std::launch::async | std::launch::deferred, threadFunc, i);的简化形式。

这里引出async和thread的区别:

1、thread是创建线程,当资源紧张无法创建时程序会异常。
2、async是异步任务,当参数是std::launch::async时也会创建进程,但资源紧张系统无法创建线程时则不创建,此时的用法同参数std::launch::deferred。
3、std::launch::deferred延时调用,不创建进程,只是等到调用std::future<>::get()方法时才进行调用,但还是在同一个线程中。
4、std::launch::async | std::launch::deferred 同时使用,是创建线程还是延时调用,取决于系统。所以在我们想创建线程时要明确指定参数std::launch::async.
创建一个异步任务函数,打印其线程id与主线程id相比较,就能看出std::launch::async和std::launch::deferred的区别。

二、promise<T>

示例如下,用可调用对象做promise的类型。


using T = function<int(int, int)>;
int calpuls(int a,int b)
{
	return a + b;
}
void threadfunc1(promise<T> &pm)
{
	cout << "threadfunc1 id:" << this_thread::get_id << endl;
	this_thread::sleep_for(chrono::seconds(3));
	pm.set_value(bind(&calpuls, std::placeholders::_1, std::placeholders::_2));
}
void thread2(future<T> &ft)
{
	cout << "thread2 id:" << this_thread::get_id << endl;
	auto f = ft.get();
	cout << f(5, 8) << endl;
}

int main()
{
	cout << "main id:" << this_thread::get_id() << endl;
	promise<T> pmt;                         //定义promise
	future<T> ftt = pmt.get_future();       //绑定future
	thread t1(threadfunc1, std::ref(pmt));  //一定要用ref
	thread t2(thread2, std::ref(ftt));
	t1.join();
	t2.join();

	cout << "main end!" << endl;
	
	return 0;
}

thread2要等待线程threadfunc1的执行,可见也是线程间同步。

三、packaged_task<T>

上文我们promise的类型是function<>包装的可调用对象,其实packaged_task<>主要的功能就是包装一个可调用对象,跟function<T>功能类似,并获取异步调用的结果。?

即他同function<T>一样都是包装可调用对象,但packaged_task<>还能通过future<>获取异步调用的结果。

using T = packaged_task<int(int)>; //可以考虑下用function<int(int)>情况是怎样的
std::deque<T> task_q;
std::mutex mu;
std::condition_variable cond;
int factorial(int i)
{
	return i*i*i;
}

void thread_1()
{
	T t;
	{
		std::unique_lock<std::mutex> locker(mu);
		cond.wait(locker, []() { return !task_q.empty(); });
		t = std::move(task_q.front());  //只能移动,拷贝构造是被删除的
		task_q.pop_front();
	}
	t(3);  //用function<int(int)>只能这里获取结果
}

int main()
{
	std::thread t1(thread_1);
	T t(factorial);
	future<int> fui = t.get_future();
	{
		std::lock_guard<std::mutex> locker(mu);
		task_q.push_back(std::move(t));
	}
	cond.notify_one();
	t1.join();
	cout << "异步调用结果:" << fui.get() << endl; //用packaged_task<>包装后,主线程能获取到执行结果

	return 0;
}

四、future<>、shared_future<>

future<T>获取结果用get(),不获取结果用wait();但只能get()一次,要多次get()需要用shared_future<>.

//第一个线程进行耗时运算
int threadadd(int a, int b)
{
	this_thread::sleep_for(chrono::seconds(2));
	return a + b;
}
//一下两个线程需要线程1的计算结果
void thread1( shared_future<int>& sf )
{
	cout << "thread1 id=" << this_thread::get_id() << " sf.get()=" << sf.get() << endl;	
}
void thread2(shared_future<int>& sf)
{
	cout << "thread1 id=" << this_thread::get_id() << " sf.get()=" << sf.get() << endl;
}

int main()
{
	packaged_task<int(int,int)> pt(threadadd);
	future<int> fui = pt.get_future();
	shared_future<int> sfu = fui.share(); //通过share()转成shared_future

	thread at(std::move(pt), 6, 7);    //packaged_task包装一个函数指针,目的是能获取函数运行结果
	thread t1(thread1,std::ref(sfu));  //以下两个线程都需要at线程的运行结果
	thread t2(thread2, std::ref(sfu)); //这里的参数一定要是shared_future,因为future<>::get()只能一次(所以是移动)
	at.join();
	t1.join();
	t2.join();

	return 0;
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:18:35  更:2022-03-24 00:20:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:14:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码