Tương lai so với lời hứa


134

Tôi đang bối rối với sự khác biệt giữa một tương lai và một lời hứa.

Rõ ràng, họ có các phương pháp và công cụ khác nhau, nhưng trường hợp sử dụng thực tế là gì?

Là nó?:

  • Khi tôi quản lý một số tác vụ không đồng bộ, tôi sử dụng tương lai để nhận giá trị "trong tương lai"
  • Khi tôi là tác vụ không đồng bộ, tôi sử dụng lời hứa làm kiểu trả về để cho phép người dùng nhận được tương lai từ lời hứa của tôi

1
Tôi đã viết một chút về điều này trong câu trả lời này .
Kerrek SB

1
bản sao có thể của std :: lời hứa là gì?
Nicol Bolas

Câu trả lời:


162

Tương lai và Hứa hẹn là hai mặt riêng biệt của hoạt động không đồng bộ.

std::promise được sử dụng bởi "nhà sản xuất / nhà văn" của hoạt động không đồng bộ.

std::future được sử dụng bởi "người tiêu dùng / người đọc" của hoạt động không đồng bộ.

Lý do nó được tách thành hai "giao diện" riêng biệt này là để ẩn chức năng "ghi / đặt" khỏi "người tiêu dùng / người đọc".

auto promise = std::promise<std::string>();

auto producer = std::thread([&]
{
    promise.set_value("Hello World");
});

auto future = promise.get_future();

auto consumer = std::thread([&]
{
    std::cout << future.get();
});

producer.join();
consumer.join();

Một cách (chưa hoàn thành) để triển khai std :: async bằng cách sử dụng std :: hứa có thể là:

template<typename F>
auto async(F&& func) -> std::future<decltype(func())>
{
    typedef decltype(func()) result_type;

    auto promise = std::promise<result_type>();
    auto future  = promise.get_future();

    std::thread(std::bind([=](std::promise<result_type>& promise)
    {
        try
        {
            promise.set_value(func()); // Note: Will not work with std::promise<void>. Needs some meta-template programming which is out of scope for this question.
        }
        catch(...)
        {
            promise.set_exception(std::current_exception());
        }
    }, std::move(promise))).detach();

    return std::move(future);
}

Sử dụng trình std::packaged_tasktrợ giúp (nghĩa là về cơ bản nó sẽ thực hiện những gì chúng tôi đã làm ở trên) xung quanh std::promisebạn có thể thực hiện các thao tác sau đầy đủ hơn và có thể nhanh hơn:

template<typename F>
auto async(F&& func) -> std::future<decltype(func())>
{
    auto task   = std::packaged_task<decltype(func())()>(std::forward<F>(func));
    auto future = task.get_future();

    std::thread(std::move(task)).detach();

    return std::move(future);
}

Lưu ý rằng điều này hơi khác với std::asyncnơi mà ý chí được trả về std::futurekhi thực sự bị chặn cho đến khi chuỗi kết thúc.


3
@tara cho rằng trở về std::move(something)là vô ích và nó cũng làm tổn thương (N) RVO. Hoàn nguyên bản chỉnh sửa của mình.
polkovnikov.ph

Trong Visual Studio 2015, vui lòng sử dụng std :: cout << tương lai.get (). C_str ();
Damian

6
Đối với những người vẫn còn bối rối, xem câu trả lời này .
kawing-chiu

2
Đó là nhà sản xuất - người tiêu dùng một lần, IMHO không thực sự là nhà sản xuất - mẫu người tiêu dùng.
Martin Meeser
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.