Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






P. Set_value(res);






}

catch (...) { // Ой: не могу получить res

p.set_exception(std:: current_exception());

}

 

Это все хорошо, но как мне получить пару соответствующих друг другу объектов future / promise – один объект в моем потоке, а другой – в каком-то другом? Ну, поскольку объекты future и promise могут перемещаться (но не копироваться), то решить это можно самыми разными способами. Наиболее очевидный подход заключается в следующем: при запуске задачи передать ей объект promise и оставить вызывающему коду соответствующий объект future, куда будет помещен результат. Использование async() является наиболее экстремальным и элегантным способом использования этого подхода.

Тип package_task предоставляет простой способ запуска потока для выполнения задачи. В том числе, он заботится об установке объекта future, связанного с соответствующим объектом promise и предоставляет обертку для помещения результата или исключения из задачи в promise. Например:

double comp(vector< double> & v)

{

// упаковываем задачи:

// (в качестве задачи мы используем стандартный

// метод accumulate() для массива double):

packaged_task< double(double*, double*, double)> pt0{

std:: accumulate< double*, double*, double> };

packaged_task< double(double*, double*, double)> pt1{

std:: accumulate< double*, double*, double> };

auto f0 = pt0.get_future(); // получаем future

auto f1 = pt1.get_future();

pt0(& v[0], & v[v.size()/2], 0); // запускаем потоки

pt1(& v[v.size()/2], & v[size()], 0);

return f0.get()+f1.get(); // получаем результаты

}

 

См. также:

  • Standard: 30.6 Futures [futures]
  • Anthony Williams: Moving Futures - Proposed Wording for UK comments 335, 336, 337 and 338. N2888==09-0078.
  • Detlef Vollmann, Howard Hinnant, and Anthony Williams An Asynchronous Future Value (revised) N2627=08-0137.
  • Howard E. Hinnant: Multithreading API for C++0X - A Layered Approach. N2094=06-0164. The original proposal for a complete threading package..

 

std:: async()

Метод async(), предназначен для простого запуска задач, является единственной возможностью, которая не утверждена в черновом варианте стандарта. Я ожидаю, что она будет принята в октябре, после переработки двух немного отличающихся предложений.

Вот пример того, как программист может подняться над всеми этими непонятными потоками и блокировками в многопоточном программировании.



// простой функтор аккумулятора

template< class T, class V> struct Accum {

T* b;

T* e;

V val;

Accum(T* bb, T* ee, const V& v): b{bb}, e{ee}, val{vv} {}

V operator() () { return std:: accumulate(b, e, val); }

};

double comp(vector< double> & v)

// запускаемнесколько задач, если v содержит

// довольно много элементов

{

if (v.size()< 10000)

return std:: accumulate(v.begin(), v.end(), 0.0);

auto f0 {async(Accum{& v[0], & v[v.size()/4], 0.0})};

auto f1 {async(Accum{& v[v.size()/4], & v[v.size()/2], 0.0})};

auto f2 {async(Accum{& v[v.size()/2], & v[v.size()*3/4], 0.0})};

auto f3 {async(Accum{& v[v.size()*3/4], & v[v.size()], 0.0})};

return f0.get()+f1.get()+f2.get()+f3.get();

}

 

Это очень простой способ использования многопоточного программирования (обратите внимание на использования «магических чисел»), но обратите внимание на отсутствие явного использования потоков, блокировок, буферов и т.п. Тип переменных f xопределяется типом возвращаемого значения функции стандартной библиотеки async(), которая возвращает future. В случае необходимости, вызов метода get() объекта типа future ожидает завершения потока. В данном случае, обязанностью метода async() является порождение потоков, а задачей объектов future является вызов join() для ожидания завершения соответствующих потоков. «Простота» является самым важным аспектом дизайна async() / future; тип future может быть использован вручную при работе с потоками, но даже и не думайте использовать async() для запуска задач, выполняющих ввод/вывод, использующих мьютексы или каким-то другим способом взаимодействующих с другими задачами. Идея создания async() аналогична идее, лежащей в основе range-for оператора: предоставить простой механизм обработки самых простых и довольно распространенных случаев, и оставить базовые механизмы для более сложных случаев.

Вызывающий код может указать, чтобы метод async() запускал новый поток, использовал любой поток, кроме вызывающего или же запускал задачу в новом потоке, только если async() «считает», что это того стоит. Последний вариант является самым простым с точки зрения пользователя и потенциально самым эффективным ((только) для простых задач).

См. также:

  • Standard:???
  • Lawrence Crowl: An Asynchronous Call for C++. N2889 = 09-0079.
  • Herb Sutter: A simple async() N2901 = 09-0091.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.