C++ 11 线程 promise、future、async、packaged_task

1.promise和future

future和promise的作用是在不同线程之间传递数据。使用指针也可以完成数据的传递,但是指针非常危险,因为互斥量不能阻止指针的访问;而且指针的方式传递的数据是固定的,如果更改数据类型,那么还需要更改有关的接口,比较麻烦;promise支持泛型的操作,更加方便编程处理。

假设线程1需要线程2的数据,那么组合使用方式如下:

线程1初始化一个promise对象和一个future对象,promise传递给线程2,相当于线程2对线程1的一个承诺;future相当于一个接受一个承诺,用来获取未来线程2传递的值
线程2获取到promise后,需要对这个promise传递有关的数据,之后线程1的future就可以获取数据了。
如果线程1想要获取数据,而线程2未给出数据,则线程1阻塞,直到线程2的数据到达。

线程1只要检测到数据到达,get就可以返回,线程2的状态可以结束也可能继续运行。

// threadTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>

// 计算一个vector数组的和,并设置一个promise,这是一个承诺,需要设置这个值
void accumulate(std::vector<int>::iterator first,
	std::vector<int>::iterator last,
	std::promise<int> accumulate_promise)
{
	int sum = std::accumulate(first, last, 0);
	std::cout << "set promise\n";
	accumulate_promise.set_value(sum);// Notify future
	std::this_thread::sleep_for(std::chrono::seconds(10));
}

void do_work(std::promise<void> barrier)
{
	std::this_thread::sleep_for(std::chrono::seconds(1));
	barrier.set_value();
	std::this_thread::sleep_for(std::chrono::seconds(10));
}

int main()
{
	// Demonstrate using promise<int> to transmit a result between threads.
	std::vector<int> numbers = { 1,2,3,4,5,6 };
	std::promise<int> accumulate_promise;
	std::future<int> accumulate_future = accumulate_promise.get_future();
	std::thread work_thread(accumulate, numbers.begin(), numbers.end(), std::move(accumulate_promise));

	std::cout << "result=" << accumulate_future.get() << "\n";
	work_thread.join();

	std::promise<void> barrier;
	std::future<void> barrier_future = barrier.get_future();
	std::thread new_work_thread(do_work, std::move(barrier));
	barrier_future.wait();
	new_work_thread.join();
    return 0;
}

2.async

(高级封装future和thread)

runs a function asynchronously (potentially in a new thread) and returns a std::future that will hold the result

异步运行一个函数(可能在新线程中)并返回将保存结果的std :: future

// threadTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>

bool is_prime(int x)
{
	for (int i = 2; i < x; i++) {
		if (x%i == 0)
			return false;
	}
	return true;
}

int main()
{
	// call function asynchronously;
	std::future<bool> fut = std::async(is_prime, 4444444443);

	// do something while waiting for function to set future.
	std::cout << "checking,please wait...";
	std::chrono::milliseconds span(100);
	while (fut.wait_for(span) == std::future_status::timeout)
	{
		std::cout << '.' << std::flush;
	}
	bool x = fut.get();
	std::cout << "\n4444444443 " << (x ? "is" : "is not") << " prime.\n";

    return 0;
}

运行结果:

std::async会首先创建线程执行is_prime(4444444443), 任务创建之后,std::async立即返回一个std::future对象。

 主线程既可使用std::future::get获取结果,如果调用过程中,任务尚未完成,则主线程阻塞至任务完成。

 主线程也可使用std::future::wait_for等待结果返回,wait_for可设置超时时间,如果在超时时间之内任务完成,则返回std::future_status::ready状态;如果在超时时间之内任务尚未完成,则返回std::future_status::timeout状态。

3.packaged_task

std::packaged_task的作用就是提供一个不同线程之间的数据同步机制,它可以存储一个函数操作,并将其返回值传递给对应的future, 而这个future在另外一个线程中也可以安全的访问到这个值。

示例代码:

// threadTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>

int countdown(int from, int to)
{
	for (int i = from; i != to; --i)
	{
		std::cout << i << '\n';
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
	std::cout << "Lift off!\n";
	return from - to;
}

int main()
{
	std::packaged_task<int(int, int)> tsk(countdown);
	std::future<int> ret = tsk.get_future();
	std::thread th(std::move(tsk), 10, 0);
	// ...
	int value = ret.get();// wait for the task to finish and get result
	std::cout << "The countdown lasted for " << value << " seconds.\n";
	th.join();
    return 0;
}

运行结果:

发布了257 篇原创文章 · 获赞 22 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_24127015/article/details/104819447