33 Thread support library [thread]

33.6 Futures [futures]

33.6.1 Overview [futures.overview]

[futures] описывает компоненты, которые программа на C ++ может использовать для получения в одном потоке результата (значения или исключения) от функции, которая выполнялась в том же или другом потоке. [ Note: Эти компоненты не ограничиваются многопоточными программами, но также могут быть полезны в однопоточных программах. ] end note

33.6.2 Header <future> synopsis [future.syn]

namespace std {
  enum class future_errc {
    broken_promise = implementation-defined,
    future_already_retrieved = implementation-defined,
    promise_already_satisfied = implementation-defined,
    no_state = implementation-defined
  };

  enum class launch : unspecified {
    async = unspecified,
    deferred = unspecified,
    implementation-defined
  };

  enum class future_status {
    ready,
    timeout,
    deferred
  };

  template <> struct is_error_code_enum<future_errc> : public true_type { };
  error_code make_error_code(future_errc e) noexcept;
  error_condition make_error_condition(future_errc e) noexcept;

  const error_category& future_category() noexcept;

  class future_error;

  template <class R> class promise;
  template <class R> class promise<R&>;
  template <> class promise<void>;

  template <class R>
    void swap(promise<R>& x, promise<R>& y) noexcept;

  template <class R, class Alloc>
    struct uses_allocator<promise<R>, Alloc>;

  template <class R> class future;
  template <class R> class future<R&>;
  template <> class future<void>;

  template <class R> class shared_future;
  template <class R> class shared_future<R&>;
  template <> class shared_future<void>;

  template <class> class packaged_task;   // not defined
  template <class R, class... ArgTypes>
    class packaged_task<R(ArgTypes...)>;

  template <class R, class... ArgTypes>
    void swap(packaged_task<R(ArgTypes...)>&, packaged_task<R(ArgTypes...)>&) noexcept;

  template <class R, class Alloc>
    struct uses_allocator<packaged_task<R>, Alloc>;

  template <class F, class... Args>
    future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
    async(F&& f, Args&&... args);
  template <class F, class... Args>
    future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
    async(launch policy, F&& f, Args&&... args);
}

enum Типа launch является bitmask type с элементами launch​::​async и launch​::​deferred. [ Note: Реализации могут предоставлять битовые маски для указания ограничений на взаимодействие задач с помощью функций, запускаемых async() применимыми к соответствующему подмножеству доступных политик запуска. Реализации могут расширять поведение первой перегрузки async() , добавляя свои расширения в политику запуска в соответствии с правилом «как если бы». ] end note

Значения перечисления future_­errc различны и не равны нулю.

33.6.3 Error handling [futures.errors]

const error_category& future_category() noexcept;

Returns:  Ссылка на объект типа, производного от класса error_­category.

Объектные default_­error_­condition и эквивалентные виртуальные функции должны вести себя, как указано для класса error_­category. name Виртуальная функция объекта должна возвращать указатель на строку "future".

error_code make_error_code(future_errc e) noexcept;

Returns: error_­code(static_­cast<int>(e), future_­category()).

error_condition make_error_condition(future_errc e) noexcept;

Returns: error_­condition(static_­cast<int>(e), future_­category()).

33.6.4 Class future_­error [futures.future_error]

namespace std {
  class future_error : public logic_error {
  public:
    explicit future_error(future_errc e);

    const error_code& code() const noexcept;
    const char*       what() const noexcept;
  private:
    error_code ec_;  // exposition only
  };
}

explicit future_error(future_errc e);

Effects: Создает объект класса future_­error и инициализируется ec_­ с помощью make_­error_­code(e).

const error_code& code() const noexcept;

Returns: ec_­.

const char* what() const noexcept;

Returns: An НТБ включения code().message().

33.6.5 Shared state [futures.state]

Многие из классов, представленных в этом подпункте, используют некоторое состояние для передачи результатов. Он shared state состоит из некоторой информации о состоянии и некоторой информации (возможно, еще не оцененной) result, которая может быть (возможно, недействительной) значением или исключением. [ Note: Фьючерсы, обещания и задачи, определенные в этом пункте, ссылаются на такое совместно используемое состояние. ] end note

[ Note: Результатом может быть любой объект, включая функцию для вычисления этого результата, как это используется async when policy is launch​::​deferred. ] end note

An asynchronous return object - это объект, который считывает результаты из общего состояния. Объект waiting function асинхронного возврата - это объект, который потенциально блокирует ожидание готовности общего состояния. Если ожидающая функция может вернуться до того, как состояние будет подготовлено из-за тайм-аута ([thread.req.lockable]), то это a timed waiting function, в противном случае - non-timed waiting function.

An asynchronous provider - это объект, который предоставляет результат для общего состояния. Результат общего состояния устанавливается соответствующими функциями асинхронного провайдера. [ Note: Например, обещания или задачи. ] Средства установки результата общего состояния указаны в описании тех классов и функций, которые создают такой объект состояния.end note

Когда говорится, что асинхронный возвращаемый объект или асинхронный провайдер освобождает свое общее состояние, это означает:

  • если возвращаемый объект или поставщик содержит последнюю ссылку на его совместно используемое состояние, совместно используемое состояние уничтожается; а также

  • возвращаемый объект или поставщик отказывается от ссылки на свое общее состояние; а также

  • эти действия не будут блокировать общее состояние, чтобы стать готовым, за исключением того, что они могут блокироваться, если выполняются все следующие условия: общее состояние было создано вызовом std​::​async, общее состояние еще не готово, и это была последняя ссылка в общее состояние.

Когда говорят, что асинхронный провайдер готовит свое общее состояние, это означает:

  • во-первых, провайдер отмечает свое общее состояние как готовое; а также

  • во-вторых, провайдер разблокирует все агенты выполнения, ожидающие готовности его общего состояния.

Когда говорится, что асинхронный провайдер отказался от своего общего состояния, это означает:

  • во-первых, если это состояние не готово, провайдер

    • сохраняет объект исключения типа future_­error с условием ошибки в broken_­promise пределах его общего состояния; а потом

    • делает свое разделяемое состояние готовым;

  • во-вторых, провайдер освобождает свое общее состояние.

Общее состояние возможно ready только в том случае, если оно содержит значение или исключение, готовое к извлечению. Ожидание готовности общего состояния может вызвать код для вычисления результата в ожидающем потоке, если это указано в описании класса или функции, создающей объект состояния.

Вызов функций, которые успешно устанавливают сохраненный результат общего состояния, synchronize with вызывает функции, успешно обнаруживающие состояние готовности, являющееся результатом этого параметра. Сохранение результата (нормального или исключительного) в совместно используемом состоянии synchronizes with - успешный возврат из вызова функции ожидания в совместно используемом состоянии.

Некоторые функции (например promise​::​set_­value_­at_­thread_­exit) задерживают подготовку общего состояния до завершения вызывающего потока. Уничтожение каждого из объектов этого потока с помощью thread storage duration упорядочивается до того, как это общее состояние будет готово.

Доступ к результату того же общего состояния может conflict. [ Note: Это явно указывает, что результат общего состояния виден в объектах, которые ссылаются на это состояние в смысле data race avoidance. Например, одновременный доступ через ссылки, возвращаемые shared_­future​::​get() ([futures.shared_future]), должен использовать операции только для чтения или обеспечивать дополнительную синхронизацию. ]end note

33.6.6 Class template promise [futures.promise]

namespace std {
  template <class R>
  class promise {
  public:
    promise();
    template <class Allocator>
      promise(allocator_arg_t, const Allocator& a);
    promise(promise&& rhs) noexcept;
    promise(const promise& rhs) = delete;
    ~promise();

    // assignment
    promise& operator=(promise&& rhs) noexcept;
    promise& operator=(const promise& rhs) = delete;
    void swap(promise& other) noexcept;

    // retrieving the result
    future<R> get_future();

    // setting the result
    void set_value(see below);
    void set_exception(exception_ptr p);

    // setting the result with deferred notification
    void set_value_at_thread_exit(see below);
    void set_exception_at_thread_exit(exception_ptr p);
  };
  template <class R>
    void swap(promise<R>& x, promise<R>& y) noexcept;
  template <class R, class Alloc>
    struct uses_allocator<promise<R>, Alloc>;
}

Реализация должна предоставлять шаблон promise и две специализации, promise<R&> и promise<​void>. Они различаются только типом аргумента функций-членов set_­value и set_­value_­at_­thread_­exit, как указано в их описаниях ниже.

set_­value, set_­exception, set_­value_­at_­thread_­exit, И set_­exception_­at_­thread_­exit функция - членов ведут себя так , как будто они приобретают один семафор , связанный с объектом обещания при обновлении объекта обещания.

template <class R, class Alloc> struct uses_allocator<promise<R>, Alloc> : true_type { };

Requires: Alloc должен быть Allocator.

promise(); template <class Allocator> promise(allocator_arg_t, const Allocator& a);

Effects: создает promise объект и общее состояние. Второй конструктор использует распределитель a для выделения памяти для общего состояния.

promise(promise&& rhs) noexcept;

Effects: создает новый promise объект и передает право собственности на совместно используемое состояние rhs (если таковое имеется) на вновь созданный объект.

Postconditions: rhs не имеет общего состояния.

~promise();

Effects: Отменяет любое общее состояние ([futures.state]).

promise& operator=(promise&& rhs) noexcept;

Effects: Отменяет любое разделяемое состояние ([futures.state]), а затем как если бы promise(std​::​move(rhs)).swap(*this).

Returns: *this.

void swap(promise& other) noexcept;

Effects: Меняет общее состояние *this и other.

Postconditions: *this имеет общее состояние (если есть), которое other было до вызова swap. other имеет общее состояние (если есть), которое *this было до вызова swap.

future<R> get_future();

Returns: future<R> Объект с тем же общим состоянием как *this.

Throws: future_­error если *this не имеет общего состояния или если get_­future уже был вызван в promise с тем же общим состоянием, что и *this.

Error conditions:

  • future_­already_­retrieved if get_­future уже был вызван promise с тем же общим состоянием, что и *this.

  • no_­state если *this не имеет общего состояния.

void promise::set_value(const R& r); void promise::set_value(R&& r); void promise<R&>::set_value(R& r); void promise<void>::set_value();

Effects: Атомарно сохраняет значение r в общем состоянии и делает это состояние готовым ([futures.state]).

Throws:

  • future_­error если его общее состояние уже имеет сохраненное значение или исключение, или

  • для первой версии любое исключение, созданное конструктором, выбранным для копирования объекта R, или

  • для второй версии любое исключение, созданное конструктором, выбранным для перемещения объекта R.

Error conditions:

  • promise_­already_­satisfied если его общее состояние уже имеет сохраненное значение или исключение.

  • no_­state если *this не имеет общего состояния.

void set_exception(exception_ptr p);

Requires: p не равно нулю.

Effects: Атомарно сохраняет указатель исключения p в общем состоянии и делает это состояние готовым ([futures.state]).

Throws: future_­error если его общее состояние уже имеет сохраненное значение или исключение.

Error conditions:

  • promise_­already_­satisfied если его общее состояние уже имеет сохраненное значение или исключение.

  • no_­state если *this не имеет общего состояния.

void promise::set_value_at_thread_exit(const R& r); void promise::set_value_at_thread_exit(R&& r); void promise<R&>::set_value_at_thread_exit(R& r); void promise<void>::set_value_at_thread_exit();

Effects: Сохраняет значение r в общем состоянии, не делая это состояние немедленно готовым. Планирует, что состояние будет подготовлено к выходу из текущего потока после того, как все объекты продолжительности хранения потока, связанные с текущим потоком, будут уничтожены.

Throws:

  • future_­error если его общее состояние уже имеет сохраненное значение или исключение, или

  • для первой версии любое исключение, созданное конструктором, выбранным для копирования объекта R, или

  • для второй версии любое исключение, созданное конструктором, выбранным для перемещения объекта R.

Error conditions:

  • promise_­already_­satisfied если его общее состояние уже имеет сохраненное значение или исключение.

  • no_­state если *this не имеет общего состояния.

void set_exception_at_thread_exit(exception_ptr p);

Requires: p не равно нулю.

Effects: Сохраняет указатель исключения p в общем состоянии, не делая это состояние немедленно готовым. Планирует, что состояние будет подготовлено к выходу из текущего потока после того, как все объекты продолжительности хранения потока, связанные с текущим потоком, будут уничтожены.

Throws: future_­error если возникает состояние ошибки.

Error conditions:

  • promise_­already_­satisfied если его общее состояние уже имеет сохраненное значение или исключение.

  • no_­state если *this не имеет общего состояния.

template <class R> void swap(promise<R>& x, promise<R>& y) noexcept;

Effects: Как будто мимо x.swap(y).

33.6.7 Class template future [futures.unique_future]

Шаблон класса future определяет тип для асинхронных возвращаемых объектов, которые не разделяют свое общее состояние с другими асинхронными возвращаемыми объектами. Созданный по умолчанию future объект не имеет общего состояния. future Объект с общим состоянием может быть создан с помощью функций на asynchronous providers или с помощью конструктора перемещения и разделяет его общее состояние с первоначальным асинхронным поставщиком. Результат (значение или исключение) future объекта может быть установлен путем вызова соответствующей функции для объекта, который имеет то же общее состояние.

[ Note: Функции-члены future не синхронизируются сами с собой или с функциями-членами shared_­future. ] end note

Эффект вызова какой - либо функции - члена, кроме деструктора, оператор присваивания-ход, shareили valid на future объекте , для которого valid() == false не определено. [ Note: Действительно перейти от будущего объекта, для которого valid() == false. ] [ Реализациям рекомендуется обнаруживать этот случай и генерировать объект типа с условием ошибки . ]end noteNote: future_­error future_­errc​::​no_­state end note

namespace std {
  template <class R>
  class future {
  public:
    future() noexcept;
    future(future&&) noexcept;
    future(const future& rhs) = delete;
    ~future();
    future& operator=(const future& rhs) = delete;
    future& operator=(future&&) noexcept;
    shared_future<R> share() noexcept;

    // retrieving the value
    see below get();

    // functions to check state
    bool valid() const noexcept;

    void wait() const;
    template <class Rep, class Period>
      future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
    template <class Clock, class Duration>
      future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
  };
}

Реализация должна предоставлять шаблон future и две специализации, future<R&> и future<​void>. Они отличаются только типом возвращаемого значения и возвращаемым значением функции-члена get, как указано в ее описании ниже.

future() noexcept;

Effects: Создает empty future объект, который не относится к общему состоянию.

Postconditions: valid() == false.

future(future&& rhs) noexcept;

Effects: Move создает future объект, который ссылается на общее состояние, на которое первоначально ссылался rhs (если таковой имеется).

Postconditions:

  • valid() возвращает то же значение, что и rhs.valid() до вызова конструктора.

  • rhs.valid() == false.

~future();

Effects:

  • Освобождает любое разделяемое состояние ([futures.state]);

  • разрушает *this.

future& operator=(future&& rhs) noexcept;

Effects:

  • Освобождает любое общее состояние ([futures.state]).

  • переместить Назначает содержимое rhs в *this.

Postconditions:

  • valid() возвращает то же значение, что и rhs.valid() до присвоения.

  • rhs.valid() == false.

shared_future<R> share() noexcept;

Returns: shared_­future<R>(std​::​move(*this)).

Postconditions: valid() == false.

R future::get(); R& future<R&>::get(); void future<void>::get();

[ Note: Как описано выше, шаблон и две его требуемые специализации отличаются только типом возвращаемого значения и возвращаемым значением функции-члена get. ]end note

Effects:

  • wait()s, пока общее состояние не будет готово, затем извлекает значение, хранящееся в общем состоянии;

  • освобождает любое разделяемое состояние ([futures.state]).

Returns:

  • future​::​get() возвращает значение, v хранящееся в общем состоянии объекта как std​::​move(v).

  • future<R&>​::​get() возвращает ссылку, хранящуюся как значение в общем состоянии объекта.

  • future<void>​::​get() ничего не возвращает.

Throws: сохраненное исключение, если исключение было сохранено в общем состоянии.

Postconditions: valid() == false.

bool valid() const noexcept;

Returns: true только если *this относится к общему состоянию.

void wait() const;

Effects: Блокируется, пока не будет готово общее состояние.

template <class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;

Effects: Нет, если общее состояние содержит отложенную функцию ([futures.async]), в противном случае блокируется, пока общее состояние не будет готово или пока не истечет относительный тайм-аут ([thread.req.timing]), указанный в rel_­time .

Returns:

  • future_­status​::​deferred если общее состояние содержит отложенную функцию.

  • future_­status​::​ready если общее состояние готово.

  • future_­status​::​timeout если функция возвращается из-за истечения относительного тайм-аута ([thread.req.timing]), указанного в rel_­time .

Throws: исключения, связанные с тайм-аутом ([thread.req.timing]).

template <class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;

Effects: Нет, если общее состояние содержит отложенную функцию ([futures.async]), в противном случае блокируется, пока общее состояние не будет готово или пока не истечет абсолютный тайм-аут ([thread.req.timing]), указанный в abs_­time .

Returns:

  • future_­status​::​deferred если общее состояние содержит отложенную функцию.

  • future_­status​::​ready если общее состояние готово.

  • future_­status​::​timeout если функция возвращается, потому что истек абсолютный тайм-аут ([thread.req.timing]), указанный в abs_­time .

Throws: исключения, связанные с тайм-аутом ([thread.req.timing]).

33.6.8 Class template shared_­future [futures.shared_future]

Шаблон класса shared_­future определяет тип для асинхронных возвращаемых объектов, которые могут совместно использовать свое общее состояние с другими асинхронными возвращаемыми объектами. Созданный по умолчанию shared_­future объект не имеет общего состояния. shared_­future Объект с общим состоянием может быть создан путем преобразования из future объекта и разделяет его общее состояние с оригиналом asynchronous provider разделяемым государством. Результат (значение или исключение) shared_­future объекта может быть установлен путем вызова соответствующей функции для объекта, который имеет то же общее состояние.

[ Note: Функции-члены shared_­future не синхронизируются сами с собой, но синхронизируются с общим состоянием. ] end note

Эффект вызова какой - либо функция - член, кроме деструктора, оператор шага присваивания, оператор копирования назначения, или valid() на shared_­future объекте , для которого valid() == false не определен. [ Note: Допустимо копировать или перемещать shared_­future объект, для которого valid() есть false. ] [ Реализациям рекомендуется обнаруживать этот случай и генерировать объект типа с условием ошибки . ] end noteNote: future_­error future_­errc​::​no_­state end note

namespace std {
  template <class R>
  class shared_future {
  public:
    shared_future() noexcept;
    shared_future(const shared_future& rhs) noexcept;
    shared_future(future<R>&&) noexcept;
    shared_future(shared_future&& rhs) noexcept;
    ~shared_future();
    shared_future& operator=(const shared_future& rhs) noexcept;
    shared_future& operator=(shared_future&& rhs) noexcept;

    // retrieving the value
    see below get() const;

    // functions to check state
    bool valid() const noexcept;

    void wait() const;
    template <class Rep, class Period>
      future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
    template <class Clock, class Duration>
      future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
  };
}

Реализация должна предоставлять шаблон shared_­future и две специализации, shared_­future<R&> и shared_­future<void>. Они отличаются только типом возвращаемого значения и возвращаемым значением функции-члена get, как указано в ее описании ниже.

shared_future() noexcept;

Effects: Создает empty shared_­future объект, который не относится к общему состоянию.

Postconditions: valid() == false.

shared_future(const shared_future& rhs) noexcept;

Effects: Создает shared_­future объект, который ссылается на то же общее состояние, что и rhs (если есть).

Postconditions: valid() возвращает то же значение, что и rhs.valid().

shared_future(future<R>&& rhs) noexcept; shared_future(shared_future&& rhs) noexcept;

Effects: Move создает shared_­future объект, который ссылается на общее состояние, на которое первоначально ссылался rhs (если таковой имеется).

Postconditions:

  • valid() возвращает то же значение, которое было rhs.valid() возвращено до вызова конструктора.

  • rhs.valid() == false.

~shared_future();

Effects:

shared_future& operator=(shared_future&& rhs) noexcept;

Effects:

  • Освобождает любое разделяемое состояние ([futures.state]);

  • переместить Назначает содержимое rhs в *this.

Postconditions:

  • valid() возвращает то же значение, которое было rhs.valid() возвращено до присвоения.

  • rhs.valid() == false.

shared_future& operator=(const shared_future& rhs) noexcept;

Effects:

  • Освобождает любое разделяемое состояние ([futures.state]);

  • присваивает содержимое rhs в *this. [ Note: В результате *this относится к тому же общему состоянию, что и rhs (если есть). ] end note

Postconditions: valid() == rhs.valid().

const R& shared_future::get() const; R& shared_future<R&>::get() const; void shared_future<void>::get() const;

[ Note: Как описано выше, шаблон и две его требуемые специализации отличаются только типом возвращаемого значения и возвращаемым значением функции-члена get. ]end note

[ Note: Доступ к объекту значения, хранящемуся в общем состоянии, несинхронизирован, поэтому программисты должны применять только те операции, над R которыми не возникает гонка данных ([intro.multithread]). ]end note

Effects: wait()s, пока общее состояние не будет готово, затем извлекает значение, хранящееся в общем состоянии.

Returns:

  • shared_­future​::​get() возвращает константную ссылку на значение, хранящееся в общем состоянии объекта. [ Note: Доступ по этой ссылке после уничтожения общего состояния приводит к неопределенному поведению; этого можно избежать, если не хранить ссылку в любом хранилище с большим сроком жизни, чем у shared_­future объекта, который вернул ссылку. ] end note

  • shared_­future<R&>​::​get() возвращает ссылку, хранящуюся как значение в общем состоянии объекта.

  • shared_­future<void>​::​get() ничего не возвращает.

Throws: сохраненное исключение, если исключение было сохранено в общем состоянии.

bool valid() const noexcept;

Returns: true только если *this относится к общему состоянию.

void wait() const;

Effects: Блокируется, пока не будет готово общее состояние.

template <class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;

Effects: Нет, если общее состояние содержит отложенную функцию ([futures.async]), в противном случае блокируется, пока общее состояние не будет готово или пока не истечет относительный тайм-аут ([thread.req.timing]), указанный в rel_­time .

Returns:

  • future_­status​::​deferred если общее состояние содержит отложенную функцию.

  • future_­status​::​ready если общее состояние готово.

  • future_­status​::​timeout если функция возвращается из-за истечения относительного тайм-аута ([thread.req.timing]), указанного в rel_­time .

Throws: исключения, связанные с тайм-аутом ([thread.req.timing]).

template <class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;

Effects: Нет, если общее состояние содержит отложенную функцию ([futures.async]), в противном случае блокируется, пока общее состояние не будет готово или пока не истечет абсолютный тайм-аут ([thread.req.timing]), указанный в abs_­time .

Returns:

  • future_­status​::​deferred если общее состояние содержит отложенную функцию.

  • future_­status​::​ready если общее состояние готово.

  • future_­status​::​timeout если функция возвращается, потому что истек абсолютный тайм-аут ([thread.req.timing]), указанный в abs_­time .

Throws: исключения, связанные с тайм-аутом ([thread.req.timing]).

33.6.9 Function template async [futures.async]

Шаблон функции async предоставляет механизм для запуска функции потенциально в новом потоке и предоставляет результат функции в future объекте, с которым он разделяет общее состояние.

template <class F, class... Args> future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(F&& f, Args&&... args); template <class F, class... Args> future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(launch policy, F&& f, Args&&... args);

Requires: F и каждый Ti в Args должен удовлетворять MoveConstructible требованиям, и

INVOKE(DECAY_COPY(std::forward<F>(f)),
       DECAY_COPY(std::forward<Args>(args))...)     // see [func.require], [thread.thread.constr]

должно быть допустимым выражением.

Effects: Первая функция ведет себя так же, как вызов второй функции с policy аргументом launch​::​async | launch​::​deferred и теми же аргументами для F и Args. Вторая функция создает общее состояние, связанное с возвращаемым future объектом. Дальнейшее поведение второй функции зависит от policy аргумента следующим образом (если применяется более одного из этих условий, реализация может выбрать любую из соответствующих политик):

  • Если launch​::​async установлено policy, вызывает INVOKE(DECAY_­COPY(std​::​forward<F>(f)), DECAY_­COPY(std​::​forward<Args>(args))...) ([func.require], [thread.thread.constr]), как если бы в новом потоке выполнения, представленном thread объектом, с вызовами DECAY_­COPY() , оцениваемыми в вызвавшем потоке async. Любое возвращаемое значение сохраняется как результат в общем состоянии. Любое исключение, возникшее в результате выполнения, INVOKE(DECAY_­COPY(std​::​forward<F>(f)), DECAY_­COPY(std​::​forward<Args>(args))...) сохраняется как исключительный результат в общем состоянии. thread Объект хранится в совместно используемом состоянии и влияет на поведение любого асинхронного возврата объекты , которые ссылаются , что состояния.

  • Если launch​::​deferred установлено policy, хранит DECAY_­COPY(std​::​forward<F>(f)) и DECAY_­COPY(std​::​forward<Args>(args))... в общем состоянии. Эти копии f и args составляют deferred function. Вызов отложенной функции оценивает, INVOKE(std​::​move(g), std​::​move(xyz)) где g находится сохраненное значение, DECAY_­COPY(std​::​forward<F>(f)) а где xyz - сохраненная копия DECAY_­COPY(std​::​forward<Args>(args)).... Любое возвращаемое значение сохраняется как результат в общем состоянии. Любое исключение, возникшее в результате выполнения отложенной функции, сохраняется как исключительный результат в общем состоянии. Общее состояние не становится готовым, пока функция не завершится. Первый вызов функции ожидания без времени ([futures.state]) для асинхронного возвращаемого объекта, ссылающегося на это совместно используемое состояние, должен вызывать отложенную функцию в потоке, который вызвал функцию ожидания. После начала оценки INVOKE(std​::​move(g), std​::​move(xyz)) функция больше не считается отложенной. [ Note: Если эта политика указана вместе с другими политиками, например, при использовании policy значения launch​::​async | launch​::​deferred, реализации должны отложить вызов или выбор политики, когда параллелизм больше не может быть эффективно использован. ] end note

  • Если в политике запуска не задано значение или установлено значение, которое не указано ни в этом международном стандарте, ни в реализации, поведение не определено.

Returns: Объект типа, future<invoke_­result_­t<decay_­t<F>, decay_­t<Args>...>> который ссылается на общее состояние, созданное этим вызовом async. [ Note: Если будущее, полученное из async , перемещается за пределы локальной области видимости, другой код, который использует будущее, должен знать, что деструктор будущего может заблокироваться, чтобы общее состояние стало готовым. ] end note

Synchronization: Независимо от приведенного policy аргумента,

  • призыв async synchronizes with призывания f. [ Note: Это утверждение применяется, даже когда соответствующий future объект перемещается в другой поток. ]; а также end note

  • завершение функции f происходит до ([intro.multithread]) готовности общего состояния. [ Note: f может вообще не вызываться, поэтому его завершение может никогда не произойти. ] end note

Если реализация выбирает launch​::​async политику,

  • вызов функции ожидания на асинхронном возвращаемом объекте, который разделяет общее состояние, созданное этим async вызовом, должен блокироваться до тех пор, пока связанный поток не завершится, как если бы он был присоединен, или иначе истечет время ожидания ([thread.thread.member]);

  • связанный поток завершает synchronizes with возврат из первой функции, которая успешно определяет состояние готовности совместно используемого состояния, или возвратом из последней функции, которая освобождает совместно используемое состояние, в зависимости от того, что произойдет раньше.

Throws: system_­error если policy == launch​::​async и реализация не может запустить новый поток, или std​::​bad_­alloc если память для внутренних структур данных не может быть выделена.

Error conditions:

  • resource_­unavailable_­try_­again - если policy == launch​::​async и система не может начать новый поток.

[Example:

int work1(int value);
int work2(int value);
int work(int value) {
  auto handle = std::async([=]{ return work2(value); });
  int tmp = work1(value);
  return tmp + handle.get();    // #1
}

[ Note: Строка №1 может не привести к параллелизму, потому что async вызов использует политику по умолчанию, которая может использовать launch​::​deferred, и в этом случае лямбда может не вызываться до get() вызова; в этом случае work1 и work2 вызываются в одном потоке, и параллелизма нет. ] ]end noteend example

33.6.10 Class template packaged_­task [futures.task]

Шаблон класса packaged_­task определяет тип оболочки для функции или вызываемого объекта, чтобы возвращаемое значение функции или вызываемого объекта сохранялось в будущем при его вызове.

Когда packaged_­task объект вызывается, вызывается его сохраненная задача, а результат (нормальный или исключительный) сохраняется в общем состоянии. Любые фьючерсы, которые разделяют общее состояние, затем смогут получить доступ к сохраненному результату.

namespace std {
  template<class> class packaged_task; // not defined

  template<class R, class... ArgTypes>
  class packaged_task<R(ArgTypes...)> {
  public:
    // construction and destruction
    packaged_task() noexcept;
    template <class F>
      explicit packaged_task(F&& f);
    ~packaged_task();

    // no copy
    packaged_task(const packaged_task&) = delete;
    packaged_task& operator=(const packaged_task&) = delete;

    // move support
    packaged_task(packaged_task&& rhs) noexcept;
    packaged_task& operator=(packaged_task&& rhs) noexcept;
    void swap(packaged_task& other) noexcept;

    bool valid() const noexcept;

    // result retrieval
    future<R> get_future();

    // execution
    void operator()(ArgTypes... );
    void make_ready_at_thread_exit(ArgTypes...);

    void reset();
  };
  template <class R, class... ArgTypes>
    void swap(packaged_task<R(ArgTypes...)>& x, packaged_task<R(ArgTypes...)>& y) noexcept;
  template <class R, class Alloc>
    struct uses_allocator<packaged_task<R>, Alloc>;
}

33.6.10.1 packaged_­task member functions [futures.task.members]

packaged_task() noexcept;

Effects: Создает packaged_­task объект без общего состояния и без сохраненной задачи.

template <class F> packaged_task(F&& f);

Requires: INVOKE<R>(f, t1, t2, ..., tN), где t1, t2, ..., tN - значения соответствующих типов в ArgTypes..., должно быть допустимым выражением. Вызов копии f должен вести себя так же, как и вызов f.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, если decay_­t<F> он того же типа, что и packaged_­task<R(ArgTypes...)>.

Effects: Создает новый packaged_­task объект с общим состоянием и инициализирует сохраненную задачу объекта с помощью std​::​forward<F>(f).

Throws:

  • Любые исключения, создаваемые конструктором копирования или перемещения f.

  • Для первой версии, bad_­alloc если не удалось выделить память для внутренних структур данных.

  • Для второй версии любые исключения, созданные allocator_­traits<Allocator>​::​template rebind_­traits<unspecified>​::​allocate.

packaged_task(packaged_task&& rhs) noexcept;

Effects: Создает новый packaged_­task объект и передает владение rhsобщим состоянием *this, оставив его rhs без общего состояния. Перемещает сохраненную задачу из rhs в *this.

Postconditions: rhs не имеет общего состояния.

packaged_task& operator=(packaged_task&& rhs) noexcept;

Effects:

  • Освобождает любое разделяемое состояние ([futures.state]);

  • звонки packaged_­task(std​::​move(rhs)).swap(*this).

~packaged_task();

Effects: Отменяет любое общее состояние ([futures.state]).

void swap(packaged_task& other) noexcept;

Effects: Меняет общие состояния и сохраненные задачи *this и other.

Postconditions: *this имеет такое же общее состояние и сохраненную задачу (если есть), что и other до вызова swap. other имеет такое же общее состояние и сохраненную задачу (если есть), что и *this до вызова swap.

bool valid() const noexcept;

Returns: true только если *this есть общее состояние.

future<R> get_future();

Returns: future Объект , который разделяет то же общегосударственный как *this.

Throws: future_­error объекта в случае возникновения ошибки.

Error conditions:

  • future_­already_­retrieved if get_­future уже был вызван для packaged_­task объекта с тем же общим состоянием, что и *this.

  • no_­state если *this не имеет общего состояния.

void operator()(ArgTypes... args);

Effects: Как будто по INVOKE<R>(f, t1, t2, ..., tN), где f хранится задача *this и t1, t2, ..., tN значения в args.... Если задача возвращается нормально, возвращаемое значение сохраняется как асинхронный результат в общем состоянии *this, в противном случае сохраняется исключение, созданное задачей. Общее состояние *this готово, и все потоки, заблокированные в функции, ожидающие *this готовности общего состояния , разблокируются.

Throws: future_­error объект исключения , если нет общегосударственных или сохраненное задание уже вызван.

Error conditions:

  • promise_­already_­satisfied если сохраненная задача уже была вызвана.

  • no_­state если *this не имеет общего состояния.

void make_ready_at_thread_exit(ArgTypes... args);

Effects: Как будто по INVOKE<R>(f, t1, t2, ..., tN), где f хранится задача, а t1, t2, ..., tN какие - значения в args.... Если задача возвращается нормально, возвращаемое значение сохраняется как асинхронный результат в общем состоянии *this, в противном случае сохраняется исключение, созданное задачей. В любом случае это должно быть сделано без[futures.state]немедленного преобразования этого состояния в состояние ready ( ). Планирует подготовить общее состояние к моменту выхода из текущего потока после того, как все объекты продолжительности хранения потока, связанные с текущим потоком, будут уничтожены.

Throws: future_­error если возникает состояние ошибки.

Error conditions:

  • promise_­already_­satisfied если сохраненная задача уже была вызвана.

  • no_­state если *this не имеет общего состояния.

void reset();

Effects: Как будто *this = packaged_­task(std​::​move(f)), где f хранится задача *this. [ Note: Это создает новое общее состояние для *this. Старое состояние заброшено ([futures.state]). ] end note

Throws:

  • bad_­alloc если не удалось выделить память для нового общего состояния.

  • любое исключение, созданное конструктором перемещения задачи, хранящейся в общем состоянии.

  • future_­error с ошибкой no_­state if *this не имеет общего состояния.

33.6.10.2 packaged_­task globals [futures.task.nonmembers]

template <class R, class... ArgTypes> void swap(packaged_task<R(ArgTypes...)>& x, packaged_task<R(ArgTypes...)>& y) noexcept;

Effects: Как будто мимо x.swap(y).

template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc> : true_type { };

Requires: Alloc должен быть Allocator.