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;
}
运行结果: