Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - [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, но и в традиционных компаниях, использующих технологии для того, чтобы вдохнуть новую жизнь в свои предприятия.Дон Тапскотт и Энтони Уильямс раскрывают принципы викиномики и рассказывают потрясающие истории о том, как массы людей (как за деньги, так и добровольно) создают новости, изучают геном человека, создают ремиксы любимой музыки, находят лекарства от болезней, редактируют школьные учебники, изобретают новую косметику, пишут программное обеспечение и даже строят мотоциклы.Знания, ресурсы и вычислительные способности миллиардов людей самоорганизуются и превращаются в новую значительную коллективную силу, действующую согласованно и управляемую с помощью блогов, вики, чатов, сетей равноправных партнеров и личные трансляции.


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

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


MFC и OpenGL

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.