Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - [41]

Шрифт
Интервал

Вызывается

>X x;                                            │p->foo(42,"hello"),

>auto f1 = std::async(&X::foo, &x, 42, "hello");←┘где p=&x

>auto f2 = std::async(&X::bar, x, "goodbye");←┐ вызывается

>                                             │tmpx.bar("goodbye"),

>struct Y {                                   │где tmpx — копия x

> double operator()(double);

>};                               │Вызывается tmpy(3.141),

>                                 │где tmpy создается

>Y y;                             │из Y перемещающим

>auto f3 = std::async(Y(), 3.141)←┘конструктором

>auto f4 = std::async(std::ref(y), 2.718);←Вызывается y(2.718)


>X baz(X&);

>std::async(baz, std::ref(x); ←Вызывается baz(x)


>class move_only {

>public:

> move_only();

> move_only(move_only&&);

> move_only(move_only const&) = delete;

> move_only& operator=(move_only&&);

> move_only& operator=(move_only const&) = delete;

> void operator()();                │Вызывается tmp(), где tmp

>};                                 │конструируется с помощью

>auto f5 = std::async(move_only());←┘std::move(move_only())

По умолчанию реализации предоставлено право решать, запускает ли >std::async новый поток или задача работает синхронно, когда программа ожидает будущего результата. В большинстве случаев такое поведение вас устроит, но можно задать требуемый режим в дополнительном параметре >std::async перед вызываемой функцией. Этот параметр имеет тип >std::launch и может принимать следующие значения: >std::launch::deferred — отложить вызов функции до того момента, когда будет вызвана функция-член >wait() или >get() объекта-будущего; >std::launch::async — запускать функцию в отдельном потоке; >std::launch::deferred | std::launch::async — оставить решение на усмотрение реализации. Последний вариант подразумевается по умолчанию. В случае отложенного вызова функция может вообще никогда не выполниться. Например:

>auto f6 =                                  │Выполнять в

> std::async(std::launch::async, Y(), 1.2);←┘новом потоке

>auto f7 =

> std::async(

>  std::launch::deferred, baz, std::ref(x)); ←┐

>auto f8 = std::async(                      ←┐│Выполнять

> std::launch::deferred | std::launch::async,││при вызове

> baz, std::ref(x));                         ││wait() или get()

>auto f9 = std::async(baz, std::ref(x));    ←┼Оставить на

>                                            │усмотрение реализации

>f7.wait();←Вызвать отложенную функцию

Ниже в этой главе и далее в главе 8 мы увидим, что с помощью >std::async легко разбивать алгоритм на параллельно выполняемые задачи. Однако это не единственный способ ассоциировать объект >std::future с задачей; можно также обернуть задачу объектом шаблонного класса >std::packaged_task<> или написать код, который будет явно устанавливать значения с помощью шаблонного класса >std::promise<>. Шаблон >std::packaged_task является абстракцией более высокого уровня, чем >std::promise, поэтому начнем с него.

4.2.2. Ассоциирование задачи с будущим результатом

Шаблон класса >std::packaged_task<> связывает будущий результат с функцией или объектом, допускающим вызов. При вызове объекта >std::packaged_task<> ассоциированная функция или допускающий вызов объект вызывается и делает будущий результат готовым, сохраняя возвращенное значение в виде ассоциированных данных. Этот механизм можно использовать для построение пулов потоков (см. главу 9) и иных схем управления, например, запускать каждую задачу в отдельном потоке или запускать их все последовательно в выделенном фоновом потоке. Если длительную операцию можно разбить на автономные подзадачи, то каждую из них можно обернуть объектом >std::packaged_task<> и передать этот объект планировщику задач или пулу потоков. Таким образом, мы абстрагируем специфику задачи — планировщик имеет дело только с экземплярами >std::packaged_task<>, а не с индивидуальными функциями.

Параметром шаблона класса >std::packaged_task<> является сигнатура функции, например >void() для функции, которая не принимает никаких параметров и не возвращает значения, или >int(std::string&, double*) для функции, которая принимает неконстантную ссылку на >std::string и указатель на >double и возвращает значение типа >int. При конструировании экземпляра >std::packaged_task вы обязаны передать функцию или допускающий вызов объект, который принимает параметры указанных типов и возвращает значение типа, преобразуемого в указанный тип возвращаемого значения. Точного совпадения типов не требуется; можно сконструировать объект >std::packaged_task из функции, которая принимает >int и возвращает >float, потому что между этими типами существуют неявные преобразования.

Тип возвращаемого значения, указанный в сигнатуре функции, определяет тип объекта >std::future<>, возвращаемого функцией-членом >get_future(), а заданный в сигнатуре список аргументов используется для определения сигнатуры оператора вызова в классе упакованной задачи. Например, в листинге ниже приведена часть определения класса >std::packaged_task*, int)>.


Листинг 4.8. Определение частичной специализации >std::packaged_task

>template<>

>class packaged_task*, int)> {


Еще от автора Энтони Д Уильямс
Викиномика. Как массовое сотрудничество изменяет всё

Это знаменитый бестселлер, который научит вас использовать власть массового сотрудничества и покажет, как применять викиномику в вашем бизнесе. Переведенная более чем на двадцать языков и неоднократно номинированная на звание лучшей бизнес-книги, "Викиномика" стала обязательным чтением для деловых людей во всем мире. Она разъясняет, как массовое сотрудничество происходит не только на сайтах Wikipedia и YouTube, но и в традиционных компаниях, использующих технологии для того, чтобы вдохнуть новую жизнь в свои предприятия.Дон Тапскотт и Энтони Уильямс раскрывают принципы викиномики и рассказывают потрясающие истории о том, как массы людей (как за деньги, так и добровольно) создают новости, изучают геном человека, создают ремиксы любимой музыки, находят лекарства от болезней, редактируют школьные учебники, изобретают новую косметику, пишут программное обеспечение и даже строят мотоциклы.Знания, ресурсы и вычислительные способности миллиардов людей самоорганизуются и превращаются в новую значительную коллективную силу, действующую согласованно и управляемую с помощью блогов, вики, чатов, сетей равноправных партнеров и личные трансляции.


Рекомендуем почитать
Программное обеспечение и его разработка

Автор книги — американский специалист по программированию, один из руководителей фирмы IBM, в своей книге делает попытку изложить общие проблемы создания программного обеспечения, его сопровождения и использования. Особенно подробно рассматриваются все фазы разработки программ разных типов. Изложение ясное, удачно иллюстрировано примерами.Для программистов разной квалификации и пользователей ЭВМ.fb2: ВНИМАНИЕ. В тексте присутствуют таблицы. Рекомендуется читать файл с помощью программы, поддерживающей их отображение.


Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Программирование приложений для мобильных устройств под управлением Android. Часть 1

Книга посвящена разработке программ для мобильных устройств под управлением операционной системы Android. Рассматривается создание приложений с использованием системных компонентов и служб Android. Приведены базовые данные о структуре приложений, об основных классах и их методах, сопровождаемые примерами кода. Часть 1 содержит шесть глав, описывающих основные принципы создания приложений, пользовательский интерфейс, полномочия приложений, а так же базовые классы: Activity, Intent, Fragment. Книга предназначена для программистов, владеющих языком программирования Java и желающих освоить написание приложений, работающих под ОС Android.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


FreeBSD - полезные советы

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Тонкости дизассемблирования

Очень часто под рукой не оказывается ни отладчика, ни дизассемблера, ни даже компилятора, чтобы набросать хотя бы примитивный трассировщик. Разумеется, что говорить о взломе современных защитных механизмов в таких условиях просто смешно, но что делать если жизнь заставляет?..