Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - [39]
> std::unique_lock
> data_cond.wait(lk, [this]{return !data_queue.empty();});
> value = data_queue.front();
> data_queue.pop();
> }
>};
>threadsafe_queue
(1)
>void data_preparation_thread() {
> while (more_data_to_prepare()) {
> data_chunk const data = prepare_data();
> data_queue.push(data); ←
(2)
> }
>}
>void data_processing_thread() {
> while (true) {
> data_chunk data;
> data_queue.wait_and_pop(data); ←
(3)
> process(data);
> if (is_last_chunk(data))
> break;
> }
>}
Теперь мьютекс и условная переменная находятся в экземпляре >threadsafe_queue
, поэтому не нужно ни отдельных переменных (1), ни внешней синхронизации при обращении к функции >push()
(2). Кроме того, >wait_and_pop()
берет на себя заботу об ожидании условной переменной (3).
Второй перегруженный вариант >wait_and_pop()
тривиален, а остальные функции можно почти без изменений скопировать из кода стека в листинге 3.5. Ниже приведена окончательная реализация.
Листинг 4.5. Полное определение класса потокобезопасной очереди на базе условных переменных
>#include
>#include
>#include
>#include
>template
>class threadsafe_queue {
>private:
> mutable std::mutex mut;←
(1) Мьютекс должен быть изменяемым
> std::queue
> std::condition_variable data_cond;
>public:
> threadsafe_queue() {}
> threadsafe_queue(threadsafe_queue const& other) {
> std::lock_guard
> data_queue = other.data_queue;
> }
> void push(T new_value) {
> std::lock_guard
> data_queue.push(new_value);
> data_cond.notify_one();
> }
> void wait_and_pop(T& value) {
> std::unique_lock
> data_cond.wait(lk, [this]{ return !data_queue.empty(); });
> value = data_queue.front();
> data_queue.pop();
> }
> std::shared_ptr
> std::unique_lock
> data_cond.wait(lk, [this]{ return !data_queue.empty(); });
> std::shared_ptr
> res(std::make_shared
> data_queue.pop();
> return res;
> }
> bool try_pop(T& value) {
> std::lock_guard
> if (data_queue.empty())
> return false;
> value = data_queue.front();
> data_queue.pop();
> return true;
> }
> std::shared_ptr
> std::lock_guard
> if (data_queue.empty())
> return std::shared_ptr
> std::shared_ptr
> res(std::make_shared
> data_queue.pop();
> return res;
> }
> bool empty() const {
> std::lock_guard
> return data_queue.empty();
> }
>};
Хотя >empty()
— константная функция-член, а параметр копирующего конструктора — >const
-ссылка, другие потоки могут хранить неконстантные ссылки на объект и вызывать изменяющие функции-члены, которые захватывают мьютекс. Поэтому захват мьютекса — это изменяющая операция, следовательно, член >mut
необходимо пометить как >mutable
(1), чтобы его можно было захватить в функции >empty()
и в копирующем конструкторе.
Условные переменные полезны и тогда, когда есть несколько потоков, ожидающих одного события. Если потоки используются для разделения работы и, следовательно, на извещение должен реагировать только один поток, то применима точно такая же структура программы, как в листинге 4.1; нужно только запустить несколько потоков обработки данных. При поступлении новых данных функция >notify_one()
разбудит только один поток, который проверяет условие внутри >wait()
, и этот единственный поток вернет управление из >wait()
(в ответ на помещение нового элемента в очередь >data_queue
). Заранее нельзя сказать, какой поток получит извещение и есть ли вообще ожидающие потоки (не исключено, что все они заняты обработкой ранее поступивших данных).
Альтернативный сценарий — когда несколько потоков ожидают одного события, и отреагировать должны все. Так бывает, например, когда инициализируются разделяемые данные, и все работающие с ними потоки должны ждать, пока инициализация завершится (хотя для этого случая существуют более подходящие механизмы, см. раздел 3.3.1 главы 3), или когда потоки должны ждать обновления разделяемых данных, например, в случае периодической повторной инициализации. В таких ситуациях поток, отвечающий за подготовку данных, может вызвать функцию-член >notify_all()
условной переменной вместо >notify_one()
. Эта функция извещает все потоки, ожидающие внутри функции >wait()
, о том, что они должны проверить ожидаемое условие.
Если ожидающий поток собирается ждать условия только один раз, то есть после того как оно станет истинным, он не вернется к ожиданию той же условной переменной, то лучше применить другой механизм синхронизации. В особенности это относится к случаю, когда ожидаемое условие — доступность каких-то данных. Для такого сценария больше подходят так называемые будущие результаты (future).
4.2. Ожидание одноразовых событий с помощью механизма будущих результатов
Предположим, вы летите самолетом в отпуск за границу. Вы приехали в аэропорт, прошли регистрацию и прочие процедуры, но должны ждать объявления о посадке — быть может, несколько часов. Можно, конечно, найти себе занятие — например, почитать книжку, побродить в Интернете, поесть в кафе за бешеные деньги, но суть от этого не меняется: вы ждете сигнала о том, что началась посадка в самолет. И есть еще одна особенность — данный рейс вылетает всего один раз; в следующий отпуск вы будете ждать посадки на другой рейс.
Это знаменитый бестселлер, который научит вас использовать власть массового сотрудничества и покажет, как применять викиномику в вашем бизнесе. Переведенная более чем на двадцать языков и неоднократно номинированная на звание лучшей бизнес-книги, "Викиномика" стала обязательным чтением для деловых людей во всем мире. Она разъясняет, как массовое сотрудничество происходит не только на сайтах 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 так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.