C++ 什么是 std::promise?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11004273/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is std::promise?
提问by Kerrek SB
I'm fairly familiar with C++11's std::thread
, std::async
and std::future
components (e.g. see this answer), which are straight-forward.
我相当熟悉C ++ 11分的std::thread
,std::async
和std::future
部件(例如见这个答案),这是直接的。
However, I cannot quite grasp what std::promise
is, what it does and in which situations it is best used. The standard document itself doesn't contain a whole lot of information beyond its class synopsis, and neither does just::thread.
但是,我不能完全理解std::promise
它是什么,它做什么以及在什么情况下最好使用它。标准文档本身不包含超出其类概要之外的大量信息,而just::thread也不包含。
Could someone please give a brief, succinct example of a situation where an std::promise
is needed and where it is the most idiomatic solution?
有人可以举一个简短的例子std::promise
来说明需要an的情况以及它是最惯用的解决方案吗?
采纳答案by Jonathan Wakely
In the words of [futures.state] a std::future
is an asynchronous return object("an object that reads results from a shared state") and a std::promise
is an asynchronous provider("an object that provides a result to a shared state") i.e. a promise is the thing that you seta result on, so that you can getit from the associated future.
用 [futures.state] 的话来说,astd::future
是一个异步返回对象(“一个从共享状态读取结果的对象”),astd::promise
是一个异步提供者(“一个向共享状态提供结果的对象”),即一个promise 是你设置结果的东西,这样你就可以从相关的未来得到它。
The asynchronous provider is what initially creates the shared state that a future refers to. std::promise
is one type of asynchronous provider, std::packaged_task
is another, and the internal detail of std::async
is another. Each of those can create a shared state and give you a std::future
that shares that state, and can make the state ready.
异步提供程序最初创建了未来引用的共享状态。std::promise
是一种异步提供者,std::packaged_task
是另一种,内部细节std::async
是另一种。每个都可以创建一个共享状态并为您提供std::future
共享该状态的一个,并且可以使状态准备好。
std::async
is a higher-level convenience utility that gives you an asynchronous result object and internally takes care of creating the asynchronous provider and making the shared state ready when the task completes. You could emulate it with a std::packaged_task
(or std::bind
and a std::promise
) and a std::thread
but it's safer and easier to use std::async
.
std::async
是一个更高级别的便利实用程序,它为您提供异步结果对象,并在内部负责创建异步提供程序并在任务完成时准备共享状态。你可以用 a std::packaged_task
(or std::bind
and a std::promise
) 和 a来模拟它,std::thread
但它更安全,更容易使用std::async
。
std::promise
is a bit lower-level, for when you want to pass an asynchronous result to the future, but the code that makes the result ready cannot be wrapped up in a single function suitable for passing to std::async
. For example, you might have an array of several promise
s and associated future
s and have a single thread which does several calculations and sets a result on each promise. async
would only allow you to return a single result, to return several you would need to call async
several times, which might waste resources.
std::promise
有点低级,因为当您想将异步结果传递给未来,但使结果准备就绪的代码不能包含在适合传递给std::async
. 例如,您可能有一个由多个promise
s 和关联的future
s 组成的数组,并且有一个线程来执行多个计算并为每个 promise 设置一个结果。async
只允许您返回一个结果,返回多个您需要async
多次调用,这可能会浪费资源。
回答by Kerrek SB
I understand the situation a bit better now (in no small amount due to the answers here!), so I thought I add a little write-up of my own.
我现在对情况有了更好的了解(由于这里的答案,数量不少!),所以我想我添加了一些我自己的文章。
There are two distinct, though related, concepts in C++11: Asynchronous computation (a function that is called somewhere else), and concurrent execution (a thread, something that does work concurrently). The two are somewhat orthogonal concepts. Asynchronous computation is just a different flavour of function call, while a thread is an execution context. Threads are useful in their own right, but for the purpose of this discussion, I will treat them as an implementation detail.
C++11 中有两个不同但相关的概念:异步计算(在别处调用的函数)和并发执行(线程,并发工作的东西)。这两者是有些正交的概念。异步计算只是函数调用的另一种形式,而线程是执行上下文。线程本身很有用,但出于本次讨论的目的,我将它们视为实现细节。
There is a hierarchy of abstraction for asynchronous computation. For example's sake, suppose we have a function that takes some arguments:
异步计算有一个抽象层次结构。例如,假设我们有一个接受一些参数的函数:
int foo(double, char, bool);
First off, we have the template std::future<T>
, which represents a future value of type T
. The value can be retrieved via the member function get()
, which effectively synchronizes the program by waiting for the result. Alternatively, a future supports wait_for()
, which can be used to probe whether or not the result is already available. Futures should be thought of as the asynchronous drop-in replacement for ordinary return types. For our example function, we expect a std::future<int>
.
首先,我们有 template std::future<T>
,它代表 type 的未来值T
。可以通过成员函数检索该值get()
,该函数通过等待结果有效地同步程序。或者,未来支持wait_for()
,可用于探测结果是否已经可用。Futures 应该被认为是普通返回类型的异步替代品。对于我们的示例函数,我们期望一个std::future<int>
.
Now, on to the hierarchy, from highest to lowest level:
现在,进入层次结构,从最高级别到最低级别:
std::async
: The most convenient and straight-forward way to perform an asynchronous computation is via theasync
function template, which returns the matching future immediately:auto fut = std::async(foo, 1.5, 'x', false); // is a std::future<int>
We have very little control over the details. In particular, we don't even know if the function is executed concurrently, serially upon
get()
, or by some other black magic. However, the result is easily obtained when needed:auto res = fut.get(); // is an int
We can now consider how to implementsomething like
async
, but in a fashion that wecontrol. For example, we may insist that the function be executed in a separate thread. We already know that we can provide a separate thread by means of thestd::thread
class.The next lower level of abstraction does exactly that:
std::packaged_task
. This is a template that wraps a function and provides a future for the functions return value, but the object itself is callable, and calling it is at the user's discretion. We can set it up like this:std::packaged_task<int(double, char, bool)> tsk(foo); auto fut = tsk.get_future(); // is a std::future<int>
The future becomes ready once we call the task and the call completes. This is the ideal job for a separate thread. We just have to make sure to movethe task into the thread:
std::thread thr(std::move(tsk), 1.5, 'x', false);
The thread starts running immediately. We can either
detach
it, or havejoin
it at the end of the scope, or whenever (e.g. using Anthony Williams'sscoped_thread
wrapper, which really should be in the standard library). The details of usingstd::thread
don't concern us here, though; just be sure to join or detachthr
eventually. What matters is that whenever the function call finishes, our result is ready:auto res = fut.get(); // as before
Now we're down to the lowest level: How would we implementthe packaged task? This is where the
std::promise
comes in. The promise is the building block for communicating with a future. The principal steps are these:The calling thread makes a promise.
The calling thread obtains a future from the promise.
The promise, along with function arguments, are moved into a separate thread.
The new thread executes the function and fulfills the promise.
The original thread retrieves the result.
As an example, here's our very own "packaged task":
template <typename> class my_task; template <typename R, typename ...Args> class my_task<R(Args...)> { std::function<R(Args...)> fn; std::promise<R> pr; // the promise of the result public: template <typename ...Ts> explicit my_task(Ts &&... ts) : fn(std::forward<Ts>(ts)...) { } template <typename ...Ts> void operator()(Ts &&... ts) { pr.set_value(fn(std::forward<Ts>(ts)...)); // fulfill the promise } std::future<R> get_future() { return pr.get_future(); } // disable copy, default move };
Usage of this template is essentially the same as that of
std::packaged_task
. Note that moving the entire task subsumes moving the promise. In more ad-hoc situations, one could also move a promise object explicitly into the new thread and make it a function argument of the thread function, but a task wrapper like the one above seems like a more flexible and less intrusive solution.
std::async
:执行异步计算的最方便和直接的方法是通过async
函数模板,它立即返回匹配的未来:auto fut = std::async(foo, 1.5, 'x', false); // is a std::future<int>
我们对细节的控制很少。特别是,我们甚至不知道该函数是并发执行的、串行执行的
get()
,还是由其他一些黑魔法执行的。但是,在需要时很容易获得结果:auto res = fut.get(); // is an int
我们现在可以考虑如何以我们控制的方式实现类似的东西。例如,我们可能会坚持在单独的线程中执行该函数。我们已经知道我们可以通过类来提供一个单独的线程。
async
std::thread
抽象的下一级正是这么做的:
std::packaged_task
。这是一个包装函数并为函数返回值提供未来的模板,但对象本身是可调用的,调用它由用户决定。我们可以这样设置:std::packaged_task<int(double, char, bool)> tsk(foo); auto fut = tsk.get_future(); // is a std::future<int>
一旦我们调用任务并且调用完成,未来就准备好了。这是单独线程的理想工作。我们只需要确保将任务移动到线程中:
std::thread thr(std::move(tsk), 1.5, 'x', false);
线程立即开始运行。我们可以使用
detach
它,或者join
在范围的末尾使用它,或者在任何时候使用它(例如使用 Anthony Williams 的scoped_thread
包装器,它确实应该在标准库中)。但是,使用的细节在std::thread
这里与我们无关;只是一定要thr
最终加入或分离。重要的是,只要函数调用完成,我们的结果就准备好了:auto res = fut.get(); // as before
现在我们下降到最低级别:我们将如何实现打包任务?这就是
std::promise
进入的地方。承诺是与未来沟通的基石。主要步骤如下:调用线程做出承诺。
调用线程从承诺中获得一个未来。
承诺与函数参数一起被移动到一个单独的线程中。
新线程执行函数并履行承诺。
原始线程检索结果。
例如,这是我们自己的“打包任务”:
template <typename> class my_task; template <typename R, typename ...Args> class my_task<R(Args...)> { std::function<R(Args...)> fn; std::promise<R> pr; // the promise of the result public: template <typename ...Ts> explicit my_task(Ts &&... ts) : fn(std::forward<Ts>(ts)...) { } template <typename ...Ts> void operator()(Ts &&... ts) { pr.set_value(fn(std::forward<Ts>(ts)...)); // fulfill the promise } std::future<R> get_future() { return pr.get_future(); } // disable copy, default move };
该模板的用法与
std::packaged_task
. 请注意,移动整个任务包含移动承诺。在更特殊的情况下,我们还可以将一个 promise 对象显式地移动到新线程中,并使其成为线程函数的函数参数,但是像上面这样的任务包装器似乎是一种更灵活且侵入性更小的解决方案。
Making exceptions
破例
Promises are intimately related to exceptions. The interface of a promise alone is not enough to convey its state completely, so exceptions are thrown whenever an operation on a promise does not make sense. All exceptions are of type std::future_error
, which derives from std::logic_error
. First off, a description of some constraints:
Promise 与异常密切相关。仅承诺的接口不足以完全传达其状态,因此只要对承诺的操作没有意义,就会抛出异常。所有异常都是std::future_error
从 派生的 类型std::logic_error
。首先,对一些约束的描述:
A default-constructed promise is inactive. Inactive promises can die without consequence.
A promise becomes active when a future is obtained via
get_future()
. However, only onefuture may be obtained!A promise must either be satisfied via
set_value()
or have an exception set viaset_exception()
before its lifetime ends if its future is to be consumed. A satisfied promise can die without consequence, andget()
becomes available on the future. A promise with an exception will raise the stored exception upon call ofget()
on the future. If the promise dies with neither value nor exception, callingget()
on the future will raise a "broken promise" exception.
默认构造的承诺是非活动的。不活跃的承诺可能会消失而没有后果。
当通过 获得未来时,承诺变为活动状态
get_future()
。然而,只能得到一个未来!如果要使用承诺,则必须在其生命周期结束之前通过 满足
set_value()
或设置异常set_exception()
。一个满意的承诺可以毫无后果地消亡,并get()
在未来变得可用。带有异常的承诺将get()
在未来调用时引发存储的异常。如果承诺既没有价值也没有异常而死亡,则调用get()
未来将引发“违背承诺”的异常。
Here is a little test series to demonstrate these various exceptional behaviours. First, the harness:
这里有一个小测试系列来演示这些不同的异常行为。一、线束:
#include <iostream>
#include <future>
#include <exception>
#include <stdexcept>
int test();
int main()
{
try
{
return test();
}
catch (std::future_error const & e)
{
std::cout << "Future error: " << e.what() << " / " << e.code() << std::endl;
}
catch (std::exception const & e)
{
std::cout << "Standard exception: " << e.what() << std::endl;
}
catch (...)
{
std::cout << "Unknown exception." << std::endl;
}
}
Now on to the tests.
现在开始测试。
Case 1: Inactive promise
案例 1:不活跃的承诺
int test()
{
std::promise<int> pr;
return 0;
}
// fine, no problems
Case 2: Active promise, unused
案例 2:主动承诺,未使用
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
return 0;
}
// fine, no problems; fut.get() would block indefinitely
Case 3: Too many futures
案例 3:期货太多
int test()
{
std::promise<int> pr;
auto fut1 = pr.get_future();
auto fut2 = pr.get_future(); // Error: "Future already retrieved"
return 0;
}
Case 4: Satisfied promise
案例 4:满意的承诺
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
}
return fut.get();
}
// Fine, returns "10".
Case 5: Too much satisfaction
案例5:过于满意
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_value(10);
pr2.set_value(10); // Error: "Promise already satisfied"
}
return fut.get();
}
The same exception is thrown if there is more than one of eitherof set_value
or set_exception
.
如果有一个以上的相同抛出异常或者的set_value
或set_exception
。
Case 6: Exception
案例 6:异常
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
pr2.set_exception(std::make_exception_ptr(std::runtime_error("Booboo")));
}
return fut.get();
}
// throws the runtime_error exception
Case 7: Broken promise
案例 7:违背诺言
int test()
{
std::promise<int> pr;
auto fut = pr.get_future();
{
std::promise<int> pr2(std::move(pr));
} // Error: "broken promise"
return fut.get();
}
回答by Paul Rubel
Bartosz Milewskiprovides a good writeup.
Bartosz Milewski提供了一篇很好的文章。
C++ splits the implementation of futures into a set of small blocks
C++将futures的实现拆分成一组小块
std::promise is one of these parts.
std::promise 是这些部分之一。
A promise is a vehicle for passing the return value (or an exception) from the thread executing a function to the thread that cashes in on the function future.
Promise 是将返回值(或异常)从执行函数的线程传递到兑现函数未来的线程的工具。
...
...
A future is the synchronization object constructed around the receiving end of the promise channel.
未来是围绕承诺通道的接收端构建的同步对象。
So, if you want to use a future, you end up with a promise that you use to get the result of the asynchronous processing.
所以,如果你想使用未来,你最终会得到一个用于获取异步处理结果的承诺。
An example from the page is:
页面上的一个例子是:
promise<int> intPromise;
future<int> intFuture = intPromise.get_future();
std::thread t(asyncFun, std::move(intPromise));
// do some other stuff
int result = intFuture.get(); // may throw MyException
回答by David Rodríguez - dribeas
In a rough approximation you can consider std::promise
as the other end of a std::future
(this is false, but for illustration you can think as if it was). The consumer end of the communication channel would use a std::future
to consume the datum from the shared state, while the producer thread would use a std::promise
to write to the shared state.
在粗略的近似中,您可以将其std::promise
视为 a 的另一端std::future
(这是错误的,但为了说明,您可以认为它是)。通信通道的消费者端将使用 astd::future
从共享状态中消费数据,而生产者线程将使用 astd::promise
写入共享状态。
回答by kjp
std::promise
is the channel or pathway for information to be returned from the async function. std::future
is the synchronization mechanism thats makes the caller wait until the return value carried in the std::promise
is ready(meaning its value is set inside the function).
std::promise
是从异步函数返回信息的通道或路径。std::future
是一种同步机制,它使调用者等待,直到 中携带的返回值std::promise
准备好(意味着它的值在函数内部设置)。
回答by Zack Yezek
There are really 3 core entities in asynchronous processing. C++11 currently focuses on 2 of them.
异步处理中确实有 3 个核心实体。C++11 目前专注于其中的 2 个。
The core things you need to run some logic asynchronously are:
异步运行某些逻辑所需的核心内容是:
- The task(logic packaged as some functor object) that will RUN 'somewhere'.
- The actual processing node- a thread, a process, etc. that RUNS such functors when they are provided to it. Look at the "Command" design pattern for a good idea of how a basic worker thread pool does this.
- The result handle: Somebody needs that result, and needs an object that will GET it for them. For OOP and other reasons, any waiting or synchronization should be done in this handle's APIs.
- 将在“某处”运行的任务(打包为某个函子对象的逻辑)。
- 的实际处理节点-线程,处理等时,他们被提供给它运行这样的仿函数。查看“命令”设计模式以了解基本工作线程池如何执行此操作。
- 该结果句柄:有人需要的是结果,而需要一个对象,将得到它为他们。由于 OOP 和其他原因,任何等待或同步都应在此句柄的 API 中完成。
C++11 calls the things I speak of in (1) std::promise
, and those in (3) std::future
.
std::thread
is the only thing provided publicly for (2). This is unfortunate because real programs need to manage thread & memory resources, and most will want tasks to run on thread pools instead of creating & destroying a thread for every little task (which almost always causes unnecessary performance hits by itself and can easily create resource starvation that is even worse).
C++11 调用我在 (1)std::promise
和 (3) 中提到的东西std::future
。
std::thread
是为 (2) 公开提供的唯一内容。这是不幸的,因为真正的程序需要管理线程和内存资源,并且大多数人希望任务在线程池上运行,而不是为每个小任务创建和销毁线程(这几乎总是会导致不必要的性能下降,并且可以轻松地创建资源饥饿甚至更糟)。
According to Herb Sutter and others in the C++11 brain trust, there are tentative plans to add a std::executor
that- much like in Java- will be the basis for thread pools and logically similar setups for (2). Maybe we'll see it in C++2014, but my bet is more like C++17 (and God help us if they botch the standard for these).
根据 Herb Sutter 和 C++11 智囊团中的其他人的说法,有一个暂定计划,即添加一个std::executor
类似于 Java 中的线程池和逻辑类似设置的基础(2)。也许我们会在 C++2014 中看到它,但我打赌它更像是 C++17(如果他们在这些方面搞砸了标准,上帝会帮助我们)。
回答by Richard Chambers
A std::promise
is created as an end point for a promise/future pair and the std::future
(created from the std::promise using the get_future()
method) is the other end point. This is a simple, one shot method of providing a way for two threads to synchronize as one thread provides data to another thread through a message.
Astd::promise
被创建为 promise/future 对的端点,并且std::future
(使用该get_future()
方法从 std::promise 创建)是另一个端点。这是一种简单的一次性方法,为两个线程提供了一种同步方式,因为一个线程通过消息向另一个线程提供数据。
You can think of it as one thread creates a promise to provide data and the other thread collects the promise in the future. This mechanism can only be used once.
您可以将其视为一个线程创建一个提供数据的承诺,而另一个线程在未来收集该承诺。这种机制只能使用一次。
The promise/future mechanism is only one direction, from the thread which uses the set_value()
method of a std::promise
to the thread which uses the get()
of a std::future
to receive the data. An exception is generated if the get()
method of a future is called more than once.
promise/future机制只是一个方向,从使用a的set_value()
方法std::promise
的线程到使用get()
astd::future
的接收数据的线程。如果 Future 的get()
方法被多次调用,则会生成异常。
If the thread with the std::promise
has not used set_value()
to fulfill its promise then when the second thread calls get()
of the std::future
to collect the promise, the second thread will go into a wait state until the promise is fulfilled by the first thread with the std::promise
when it uses the set_value()
method to send the data.
如果与线程std::promise
没有使用set_value()
履行其承诺,那么当第二个线程调用get()
的std::future
收集承诺,第二个线程将进入等待状态,直到承诺通过与第一个线程完成std::promise
时,它使用的set_value()
方法发送数据。
With the proposed coroutines of Technical Specification N4663 Programming Languages — C++ Extensions for Coroutinesand the Visual Studio 2017 C++ compiler support of co_await
, it is also possible to use std::future
and std::async
to write coroutine functionality. See the discussion and example in https://stackoverflow.com/a/50753040/1466970which has as one section that discusses the use of std::future
with co_await
.
借助技术规范 N4663 编程语言 —协程的C++ 扩展和 Visual Studio 2017 C++ 编译器支持的提议协程,co_await
还可以使用std::future
和std::async
编写协程功能。请参阅https://stackoverflow.com/a/50753040/1466970 中的讨论和示例,其中一节讨论了std::future
with的使用co_await
。
The following example code, a simple Visual Studio 2013 Windows console application, shows using a few of the C++11 concurrency classes/templates and other functionality. It illustrates a use for promise/future which works well, autonomous threads which will do some task and stop, and a use where more synchronous behavior is required and due to the need for multiple notifications the promise/future pair does not work.
以下示例代码是一个简单的 Visual Studio 2013 Windows 控制台应用程序,展示了如何使用一些 C++11 并发类/模板和其他功能。它说明了对 promise/future 的使用,它运行良好,自治线程将执行一些任务并停止,以及在需要更多同步行为且由于需要多个通知的情况下使用 promise/future 对不起作用。
One note about this example is the delays added in various places. These delays were added only to make sure that the various messages printed to the console using std::cout
would be clear and that text from the several threads would not be intermingled.
关于这个例子的一个注意事项是在不同地方添加的延迟。添加这些延迟只是为了确保打印到控制台的各种消息std::cout
是清晰的,并且来自多个线程的文本不会混合在一起。
The first part of the main()
is creating three additional threads and using std::promise
and std::future
to send data between the threads. An interesting point is where the main thread starts up a thread, T2, which will wait for data from the main thread, do something, and then send data to the third thread, T3, which will then do something and send data back to the main thread.
第一部分main()
是创建三个额外的线程并使用std::promise
和std::future
在线程之间发送数据。有趣的一点是,主线程启动了一个线程 T2,它会等待来自主线程的数据,做一些事情,然后将数据发送到第三个线程 T3,然后它会做一些事情并将数据发送回主线程。主线程。
The second part of the main()
creates two threads and a set of queues to allow multiple messages from the main thread to each of the two created threads. We can not use std::promise
and std::future
for this because the promise/future duo are one shot and can not be use repeatedly.
第二部分main()
创建了两个线程和一组队列,以允许从主线程到两个创建的线程中的每一个的多条消息。我们不能使用std::promise
和std::future
为此,因为承诺/未来二人组是一次性的,不能重复使用。
The source for the class Sync_queue
is from Stroustrup's The C++ Programming Language: 4th Edition.
该类的源代码Sync_queue
来自 Stroustrup 的 The C++ Programming Language: 4th Edition。
// cpp_threads.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <thread> // std::thread is defined here
#include <future> // std::future and std::promise defined here
#include <list> // std::list which we use to build a message queue on.
static std::atomic<int> kount(1); // this variable is used to provide an identifier for each thread started.
//------------------------------------------------
// create a simple queue to let us send notifications to some of our threads.
// a future and promise are one shot type of notifications.
// we use Sync_queue<> to have a queue between a producer thread and a consumer thread.
// this code taken from chapter 42 section 42.3.4
// The C++ Programming Language, 4th Edition by Bjarne Stroustrup
// copyright 2014 by Pearson Education, Inc.
template<typename Ttype>
class Sync_queue {
public:
void put(const Ttype &val);
void get(Ttype &val);
private:
std::mutex mtx; // mutex used to synchronize queue access
std::condition_variable cond; // used for notifications when things are added to queue
std::list <Ttype> q; // list that is used as a message queue
};
template<typename Ttype>
void Sync_queue<Ttype>::put(const Ttype &val) {
std::lock_guard <std::mutex> lck(mtx);
q.push_back(val);
cond.notify_one();
}
template<typename Ttype>
void Sync_queue<Ttype>::get(Ttype &val) {
std::unique_lock<std::mutex> lck(mtx);
cond.wait(lck, [this]{return !q.empty(); });
val = q.front();
q.pop_front();
}
//------------------------------------------------
// thread function that starts up and gets its identifier and then
// waits for a promise to be filled by some other thread.
void func(std::promise<int> &jj) {
int myId = std::atomic_fetch_add(&kount, 1); // get my identifier
std::future<int> intFuture(jj.get_future());
auto ll = intFuture.get(); // wait for the promise attached to the future
std::cout << " func " << myId << " future " << ll << std::endl;
}
// function takes a promise from one thread and creates a value to provide as a promise to another thread.
void func2(std::promise<int> &jj, std::promise<int>&pp) {
int myId = std::atomic_fetch_add(&kount, 1); // get my identifier
std::future<int> intFuture(jj.get_future());
auto ll = intFuture.get(); // wait for the promise attached to the future
auto promiseValue = ll * 100; // create the value to provide as promised to the next thread in the chain
pp.set_value(promiseValue);
std::cout << " func2 " << myId << " promised " << promiseValue << " ll was " << ll << std::endl;
}
// thread function that starts up and waits for a series of notifications for work to do.
void func3(Sync_queue<int> &q, int iBegin, int iEnd, int *pInts) {
int myId = std::atomic_fetch_add(&kount, 1);
int ll;
q.get(ll); // wait on a notification and when we get it, processes it.
while (ll > 0) {
std::cout << " func3 " << myId << " start loop base " << ll << " " << iBegin << " to " << iEnd << std::endl;
for (int i = iBegin; i < iEnd; i++) {
pInts[i] = ll + i;
}
q.get(ll); // we finished this job so now wait for the next one.
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::chrono::milliseconds myDur(1000);
// create our various promise and future objects which we are going to use to synchronise our threads
// create our three threads which are going to do some simple things.
std::cout << "MAIN #1 - create our threads." << std::endl;
// thread T1 is going to wait on a promised int
std::promise<int> intPromiseT1;
std::thread t1(func, std::ref(intPromiseT1));
// thread T2 is going to wait on a promised int and then provide a promised int to thread T3
std::promise<int> intPromiseT2;
std::promise<int> intPromiseT3;
std::thread t2(func2, std::ref(intPromiseT2), std::ref(intPromiseT3));
// thread T3 is going to wait on a promised int and then provide a promised int to thread Main
std::promise<int> intPromiseMain;
std::thread t3(func2, std::ref(intPromiseT3), std::ref(intPromiseMain));
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2 - provide the value for promise #1" << std::endl;
intPromiseT1.set_value(22);
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2.2 - provide the value for promise #2" << std::endl;
std::this_thread::sleep_for(myDur);
intPromiseT2.set_value(1001);
std::this_thread::sleep_for(myDur);
std::cout << "MAIN #2.4 - set_value 1001 completed." << std::endl;
std::future<int> intFutureMain(intPromiseMain.get_future());
auto t3Promised = intFutureMain.get();
std::cout << "MAIN #2.3 - intFutureMain.get() from T3. " << t3Promised << std::endl;
t1.join();
t2.join();
t3.join();
int iArray[100];
Sync_queue<int> q1; // notification queue for messages to thread t11
Sync_queue<int> q2; // notification queue for messages to thread t12
std::thread t11(func3, std::ref(q1), 0, 5, iArray); // start thread t11 with its queue and section of the array
std::this_thread::sleep_for(myDur);
std::thread t12(func3, std::ref(q2), 10, 15, iArray); // start thread t12 with its queue and section of the array
std::this_thread::sleep_for(myDur);
// send a series of jobs to our threads by sending notification to each thread's queue.
for (int i = 0; i < 5; i++) {
std::cout << "MAIN #11 Loop to do array " << i << std::endl;
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
q1.put(i + 100);
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
q2.put(i + 1000);
std::this_thread::sleep_for(myDur); // sleep a moment for I/O to complete
}
// close down the job threads so that we can quit.
q1.put(-1); // indicate we are done with agreed upon out of range data value
q2.put(-1); // indicate we are done with agreed upon out of range data value
t11.join();
t12.join();
return 0;
}
This simple application creates the following output.
这个简单的应用程序创建以下输出。
MAIN #1 - create our threads.
MAIN #2 - provide the value for promise #1
func 1 future 22
MAIN #2.2 - provide the value for promise #2
func2 2 promised 100100 ll was 1001
func2 3 promised 10010000 ll was 100100
MAIN #2.4 - set_value 1001 completed.
MAIN #2.3 - intFutureMain.get() from T3. 10010000
MAIN #11 Loop to do array 0
func3 4 start loop base 100 0 to 5
func3 5 start loop base 1000 10 to 15
MAIN #11 Loop to do array 1
func3 4 start loop base 101 0 to 5
func3 5 start loop base 1001 10 to 15
MAIN #11 Loop to do array 2
func3 4 start loop base 102 0 to 5
func3 5 start loop base 1002 10 to 15
MAIN #11 Loop to do array 3
func3 4 start loop base 103 0 to 5
func3 5 start loop base 1003 10 to 15
MAIN #11 Loop to do array 4
func3 4 start loop base 104 0 to 5
func3 5 start loop base 1004 10 to 15
回答by Narcolessico
The promise is the other end of the wire.
承诺是电线的另一端。
Imagine you need to retrieve the value of a future
being computed by an async
. However, you don't want it to be computed in the same thread, and you don't even spawn a thread "now" - maybe your software was designed to pick a thread from a pool, so you don't know whowill perform che computation in the end.
想象一下,您需要检索future
由async
. 但是,你不希望它在同一个线程来计算,你甚至不产生一个线程,“现在” -也许你的软件被设计成从池中选择一个线程,所以你不知道谁将会最后执行che计算。
Now, what do you pass to this (yet unknown) thread/class/entity? You don't pass the future
, since this is the result. You want to pass something that is connectedto the future
and that represents the other end of the wire, so you will just query the future
with no knowledge about who will actually compute/write something.
现在,你传递给这个(但未知的)线程/类/实体什么?你没有通过future
,因为这是结果。您想传递连接到future
并且代表线路另一端的东西,因此您只需查询 ,future
而无需知道谁将实际计算/编写某些东西。
This is the promise
. It is a handleconnected to your future
. If the future
is a speaker, and with get()
you start listening until some sound comes out, the promise
is a microphone; but not just any microphone, it is themicrophone connected with a single wire to the speaker you hold. You might know who's at the other end but you don't need to know it - you just give it and wait until the other party says something.
这是promise
. 这是一个手柄连接到您future
。如果future
是扬声器,并且get()
您开始聆听直到发出声音,则promise
是麦克风;但不仅仅是任何麦克风,它是通过一根电线连接到您手持的扬声器的麦克风。您可能知道另一端是谁,但您不需要知道——您只需提供并等待对方说点什么。
回答by Zhang
http://www.cplusplus.com/reference/future/promise/
http://www.cplusplus.com/reference/future/promise/
One sentence explanation: furture::get() waits promse::set_value() forever.
一句话解释:furture::get()永远等待promse::set_value()。
void print_int(std::future<int>& fut) {
int x = fut.get(); // future would wait prom.set_value forever
std::cout << "value: " << x << '\n';
}
int main()
{
std::promise<int> prom; // create promise
std::future<int> fut = prom.get_future(); // engagement with future
std::thread th1(print_int, std::ref(fut)); // send future to new thread
prom.set_value(10); // fulfill promise
// (synchronizes with getting the future)
th1.join();
return 0;
}