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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:44:28  来源:igfitidea点击:

What is std::promise?

c++multithreadingc++11promisestandard-library

提问by Kerrek SB

I'm fairly familiar with C++11's std::thread, std::asyncand std::futurecomponents (e.g. see this answer), which are straight-forward.

我相当熟悉C ++ 11分的std::threadstd::asyncstd::future部件(例如见这个答案),这是直接的。

However, I cannot quite grasp what std::promiseis, 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::promiseis needed and where it is the most idiomatic solution?

有人可以举一个简短的例子std::promise来说明需要an的情况以及它是最惯用的解决方案吗?

采纳答案by Jonathan Wakely

In the words of [futures.state] a std::futureis an asynchronous return object("an object that reads results from a shared state") and a std::promiseis 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::promiseis one type of asynchronous provider, std::packaged_taskis another, and the internal detail of std::asyncis another. Each of those can create a shared state and give you a std::futurethat shares that state, and can make the state ready.

异步提供程序最初创建了未来引用的共享状态。std::promise是一种异步提供者,std::packaged_task是另一种,内部细节std::async是另一种。每个都可以创建一个共享状态并为您提供std::future共享该状态的一个,并且可以使状态准备好。

std::asyncis 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::bindand a std::promise) and a std::threadbut it's safer and easier to use std::async.

std::async是一个更高级别的便利实用程序,它为您提供异步结果对象,并在内部负责创建异步提供程序并在任务完成时准备共享状态。你可以用 a std::packaged_task(or std::bindand a std::promise) 和 a来模拟它,std::thread但它更安全,更容易使用std::async

std::promiseis 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 promises and associated futures and have a single thread which does several calculations and sets a result on each promise. asyncwould only allow you to return a single result, to return several you would need to call asyncseveral times, which might waste resources.

std::promise有点低级,因为当您想将异步结果传递给未来,但使结果准备就绪的代码不能包含在适合传递给std::async. 例如,您可能有一个由多个promises 和关联的futures 组成的数组,并且有一个线程来执行多个计算并为每个 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 func­tion call, while a thread is an execution context. Threads are useful in their own right, but for the pur­pose 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 val­ue can be retrieved via the member function get(), which effectively synchronizes the program by wait­ing 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 re­place­ment 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:

现在,进入层次结构,从最高级别到最低级别:

  1. std::async: The most convenient and straight-forward way to perform an asynchronous com­pu­ta­tion is via the asyncfunction 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 exe­cu­ted concurrently, serially upon get(), or by some other black magic. However, the result is easily ob­tained when needed:

    auto res = fut.get();  // is an int
    
  2. 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 the std::threadclass.

    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 call­able, 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 se­pa­rate 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 detachit, or have joinit at the end of the scope, or whenever (e.g. using Anthony Williams's scoped_threadwrapper, which really should be in the standard library). The details of using std::threaddon't concern us here, though; just be sure to join or detach threventually. What matters is that whenever the function call finishes, our result is ready:

    auto res = fut.get();  // as before
    
  3. Now we're down to the lowest level: How would we implementthe packaged task? This is where the std::promisecomes 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.

  1. 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
    
  2. 我们现在可以考虑如何以我们控制的方式实现类似的东西。例如,我们可能会坚持在单独的线程中执行该函数。我们已经知道我们可以通过类来提供一个单独的线程。asyncstd::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
    
  3. 现在我们下降到最低级别:我们将如何实现打包任务?这就是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 via set_exception()before its lifetime ends if its future is to be consumed. A satisfied promise can die without consequence, and get()becomes available on the future. A promise with an exception will raise the stored exception upon call of get()on the future. If the promise dies with neither value nor exception, calling get()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_valueor set_exception.

如果有一个以上的相同抛出异常或者set_valueset_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::promiseas 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::futureto consume the datum from the shared state, while the producer thread would use a std::promiseto write to the shared state.

在粗略的近似中,您可以将其std::promise视为 a 的另一端std::future(这是错误的,但为了说明,您可以认为它是)。通信通道的消费者端将使用 astd::future从共享状态中消费数据,而生产者线程将使用 astd::promise写入共享状态。

回答by kjp

std::promiseis the channel or pathway for information to be returned from the async function. std::futureis the synchronization mechanism thats makes the caller wait until the return value carried in the std::promiseis 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:

异步运行某些逻辑所需的核心内容是:

  1. The task(logic packaged as some functor object) that will RUN 'somewhere'.
  2. 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.
  3. 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.
  1. 将在“某处”运行的任务(打包为某个函子对象的逻辑)。
  2. 实际处理节点-线程,处理等时,他们被提供给它运行这样的仿函数。查看“命令”设计模式以了解基本工作线程池如何执行此操作。
  3. 结果句柄:有人需要的是结果,而需要一个对象,将得到它为他们。由于 OOP 和其他原因,任何等待或同步都应在此句柄的 API 中完成。

C++11 calls the things I speak of in (1) std::promise, and those in (3) std::future. std::threadis 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::futurestd::thread是为 (2) 公开提供的唯一内容。这是不幸的,因为真正的程序需要管理线程和内存资源,并且大多数人希望任务在线程池上运行,而不是为每个小任务创建和销毁线程(这几乎总是会导致不必要的性能下降,并且可以轻松地创建资源饥饿甚至更糟)。

According to Herb Sutter and others in the C++11 brain trust, there are tentative plans to add a std::executorthat- 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::promiseis 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::promiseto the thread which uses the get()of a std::futureto 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::promisehas not used set_value()to fulfill its promise then when the second thread calls get()of the std::futureto collect the promise, the second thread will go into a wait state until the promise is fulfilled by the first thread with the std::promisewhen 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::futureand std::asyncto 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::futurewith co_await.

借助技术规范 N4663 编程语言 —协程的C++ 扩展和 Visual Studio 2017 C++ 编译器支持的提议协程,co_await还可以使用std::futurestd::async编写协程功能。请参阅https://stackoverflow.com/a/50753040/1466970 中的讨论和示例,其中一节讨论了std::futurewith的使用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::coutwould 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::promiseand std::futureto 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::promisestd::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::promiseand std::futurefor this because the promise/future duo are one shot and can not be use repeatedly.

第二部分main()创建了两个线程和一组队列,以允许从主线程到两个创建的线程中的每一个的多条消息。我们不能使用std::promisestd::future为此,因为承诺/未来二人组是一次性的,不能重复使用。

The source for the class Sync_queueis 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 futurebeing 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.

想象一下,您需要检索futureasync. 但是,你不希望它在同一个线程来计算,你甚至不产生一个线程,“现在” -也许你的软件被设计成从池中选择一个线程,所以你不知道将会最后执行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 futureand that represents the other end of the wire, so you will just query the futurewith 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 futureis a speaker, and with get()you start listening until some sound comes out, the promiseis 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;
}