tasks是最新额外添加的C++标准。
这是给了一个比线程更好的抽象。
通常情况下,这应该是你的第一选择。
Tasks行为就像是数据通道。
一方面,发送者设置一个值。
另一方面,接收者获取这个值。
发送这人通常被称为promise, 接收者被称为future.
或者换句话说就是, 发送者承诺提供一个值, 接收者在将来可以获取到它。
来看一些更多的细节。
- 发送者可以提供给多个future。
- 除了值,发送者还可以提供通知或者异常。
- future阻塞调用get。
这意味着,如果future要调用get,它必须等到promise把值放进数据通道中。
tasks 三种变体
1、被异步函数std::async
所调用。
2、使用std::packaged_task
为一个callable作为一个简单的包装
3、一个明确的pair,std::promise
和 std::future
想要知道线程和tasks的区别,最好的方法就是比较它们。
线程和tasks对比
让我们用简单的代码阐明它们的不同之处:
int res;
std::thread t([&]
{
res = 3 + 4;
});
t.join();
std::cout << res << std::endl;
auto fut = std::async([]
{
return 3 + 4;
});
std::cout << fut.get() << std::endl;
无论子线程还是promise都计算了3+4的和,并且返回了执行结果.
std::async的调用在fut和std::async两端生成了一个数据通道。
fut是个future,std::async是个promise。
future通过调用fut.get()获取值。当然值是由promise提供的。
future值的获取可以在稍后的时间点执行。
那区别是啥啊?
- 线程需要
<thread>
头文件,而task需要<future>
头文件。 - 线程的参与者是创建主线程和子线程,task的参与者是promise和future。
- 线程操作的共享变量res是通过子线程传递给父线程方式计算的结果。
- 然而promise 和 future使用一个公共的数据通道,std::async创建的这个数据通道,使用future变量fut.get获取计算的结果。
- 使用线程你必须使用锁来保护共享变量。
- 但是promise 和 future不会有机会出现竞争条件。
- 主线程等待子线程结束需要子线程调用join函数;然而fut.get 调用直接阻塞。
- 如果子线程中存在异常,则子线程和创建者线程终止,最终整个程序gg。
- 然而promise可以为future返回一个异常,future必须处理这个异常。
- 子线程只能通过值向主线程传递数据,但是promise能传递值,异常,消息通知等给future。
线程和task关键的区别在于tasks的抽象级别更高。
tasks不会自动生成线程,确切地说,C++在运行时决定是否应该创建一个线程。
决定的依据是:有效载荷有多重?有多少核心可用?系统负载有多高?
原文地址:
http://www.modernescpp.com/index.php/tasks