Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - [11]
Мы начнем эту главу с рассмотрения базовых операций: запуск потока, ожидание его завершения, исполнение в фоновом режиме. Затем мы поговорим о передаче дополнительных параметров функции потока в момент запуска и о том, как передать владение потока от одного объекта >std::thread
другому. Наконец, мы обсудим вопрос о том, сколько запускать потоков и как идентифицировать отдельный поток.
2.1. Базовые операции управления потоками
В каждой программе на С++ имеется по меньшей мере один поток, запускаемый средой исполнения С++: тот, в котором исполняется функция >main()
. Затем программа может запускать дополнительные потоки с другими функциями в качестве точки входа. Эти потоки работают параллельно друг с другом и с начальным потоком. Мы знаем, что программа завершает работу, когда >main()
возвращает управление; точно так же, при возврате из точки входа в поток этот поток завершается. Ниже мы увидим, что, имея объект >std::thread
для некоторого потока, мы можем дождаться завершения этого потока, но сначала посмотрим, как потоки запускаются.
2.1.1. Запуск потока
В главе 1 мы видели, что для запуска потока следует сконструировать объект >std::thread
, который определяет, какая задача будет исполняться в потоке. В простейшем случае задача представляет собой обычную функцию без параметров, возвращающую >void
. Эта функция работает в своем потоке, пока не вернет управление, и в этом момент поток завершается. С другой стороны, в роли задачи может выступать объект-функция, который принимает дополнительные параметры и выполняет ряд независимых операций, информацию о которых получает во время работы от той или иной системы передачи сообщений. И останавливается такой поток, когда получит соответствующий сигнал, опять же с помощью системы передачи сообщений. Вне зависимости от того, что поток будет делать и откуда он запускается, сам запуск потока в стандартном С++ всегда сводится к конструированию объекта >std::thread
:
>void do_some_work();
>std::thread my_thread(do_some_work);
Как видите, все просто. Разумеется, как и во многих других случаях в стандартной библиотеке С++, класс >std::thread
работает с любым типом, допускающим вызов (Callable), поэтому конструктору >std::thread
можно передать экземпляр класса, в котором определен оператор вызова:
>class background_task {
>public:
> void operator()() const {
> do_something();
> do_something_else();
> }
>};
>background_task f;
>std::thread my_thread(f);
В данном случае переданный объект-функция копируется в память, принадлежащую только что созданному потоку выполнения, и оттуда вызывается. Поэтому необходимо, чтобы с точки зрения поведения копия была эквивалентна оригиналу, иначе можно получить неожиданный результат.
При передаче объекта-функции конструктору потока нужно избегать феномена «самого досадного разбора в С++» (C++'s most vexing parse). Синтаксически передача конструктору временного объекта вместо именованной переменной выглядит так же, как объявление функции, и именно так компилятор и интерпретирует эту конструкцию. Например, в предложении
>std::thread my_thread(background_task());
объявлена функция >my_thread
, принимающая единственный параметр (типа указателя на функцию без параметров, которая возвращает объект >background_task
) и возвращающая объект >std::thread
. Никакой новый поток здесь не запускается. Решить эту проблему можно тремя способами: поименовать объект-функцию, как в примере выше; добавить лишнюю пару скобок или воспользоваться новым универсальным синтаксисом инициализации, например:
>std::thread my_thread((background_task())); ←
(1)
>std::thread my_thread{background_task()}; ←
(2)
В случае (1) наличие дополнительных скобок не дает компилятору интерпретировать конструкцию как объявление функции, так что действительно объявляется переменная >my_thread
типа >std::thread
. В случае (2) использован новый универсальный синтаксис инициализации с фигурными, а не круглыми скобками, он тоже приводит к объявлению переменной.
В стандарте С++11 имеется новый тип допускающего вызов объекта, в котором описанная проблема не возникает, — лямбда-выражение. Этот механизм позволяет написать локальную функцию, которая может захватывать некоторые локальные переменные, из-за чего передавать дополнительные аргументы просто не нужно (см. раздел 2.2). Подробная информация о лямбда-выражениях приведена в разделе А.5 приложения А. С помощью лямбда-выражений предыдущий пример можно записать в таком виде:
>std::thread my_thread([](
> do_something();
> do_something_else();
>});
После запуска потока необходимо явно решить, ждать его завершения (присоединившись к нему, см. раздел 2.1.2) или предоставить собственной судьбе (отсоединив его, см. раздел 2.1.3). Если это решение не будет принято к моменту уничтожения объекта >std::thread
, то программа завершится (деструктор >std::thread
вызовет функцию >std::terminate()
). Поэтому вы обязаны гарантировать, что поток корректно присоединен либо отсоединен, даже если возможны исключения. Соответствующая техника программирования описана в разделе 2.1.3. Отметим, что это решение следует принять именно до уничтожения объекта
Это знаменитый бестселлер, который научит вас использовать власть массового сотрудничества и покажет, как применять викиномику в вашем бизнесе. Переведенная более чем на двадцать языков и неоднократно номинированная на звание лучшей бизнес-книги, "Викиномика" стала обязательным чтением для деловых людей во всем мире. Она разъясняет, как массовое сотрудничество происходит не только на сайтах Wikipedia и YouTube, но и в традиционных компаниях, использующих технологии для того, чтобы вдохнуть новую жизнь в свои предприятия.Дон Тапскотт и Энтони Уильямс раскрывают принципы викиномики и рассказывают потрясающие истории о том, как массы людей (как за деньги, так и добровольно) создают новости, изучают геном человека, создают ремиксы любимой музыки, находят лекарства от болезней, редактируют школьные учебники, изобретают новую косметику, пишут программное обеспечение и даже строят мотоциклы.Знания, ресурсы и вычислительные способности миллиардов людей самоорганизуются и превращаются в новую значительную коллективную силу, действующую согласованно и управляемую с помощью блогов, вики, чатов, сетей равноправных партнеров и личные трансляции.
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.