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

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

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

>std::thread::id master_thread;


>void some_core_part_of_algorithm() {

> if (std::this_thread::get_id() == master_thread) {

>  do_master_thread_work();

> }

> do_common_work();

>}

Или можно было бы сохранить >std::thread::id текущего потока в некоторой структуре данных в ходе выполнения какой-то операции. В дальнейшем при операциях с той же структурой данных можно было сравнить сохраненный идентификатор с идентификатором потока, выполняющего операцию, и решить, какие операции разрешены или необходимы.

Идентификаторы потоков можно было бы также использовать как ключи ассоциативных контейнеров, если с потоком нужно ассоциировать какие-то данные, а другие механизмы, например поточно-локальная память, не подходят. Например, управляющий поток мог бы сохранить в таком контейнере информацию о каждом управляемом им потоке. Другое применение подобного контейнера — передавать информацию между потоками.

Идея заключается в том, что в большинстве случаев >std::thread::id вполне может служить обобщенным идентификатором потока и лишь, если с идентификатором необходимо связать какую-то семантику (например, использовать его как индекс массива), может потребоваться другое решение. Можно даже выводить объект >std::thread::id в выходной поток, например >std::cout:

>std::cout << std::this_thread::get_id();

Точный формат вывода зависит от реализации; стандарт лишь гарантирует, что результаты вывода одинаковых идентификаторов потоков будут одинаковы, а разных различаться. Поэтому для отладки и протоколирования это может быть полезно, но так как никакой семантики у значений идентификаторов нет, то сделать на их основе какие-то другие выводы невозможно.

2.6. Резюме

В этой главе мы рассмотрели основные средства управления потоками, имеющиеся в стандартной библиотеке С++: запуск потоков, ожидание завершения потока и отказ от ожидания вследствие того, что поток работает в фоновом режиме. Мы также научились передавать аргументы функции потока при запуске и передавать ответственность за управление потоком из одной части программы в другую. Кроме того, мы видели, как можно использовать группы потоков для разбиения задачи на части. Наконец, мы обсудили механизм идентификации потоков, позволяющий ассоциировать с потоком данные или поведение в тех случаях, когда использовать другие средства неудобно. Даже совершенно независимые потоки позволяют сделать много полезного, как видно из листинга 2.8, но часто требуется, чтобы работающие потоки обращались к каким-то общим данным. В главе 3 рассматриваются проблемы, возникающие при разделении данных между потоками, а в главе 4 — более общие вопросы синхронизации операций с использованием и без использования разделяемых данных.

Глава 3.

Разделение данных между потоками

В этой главе:

■ Проблемы разделения данных между потоками.

■ Защита данных с помощью мьютексов.

■ Альтернативные средства защиты разделяемых данных.

Одно из основных достоинств применения потоков для реализации параллелизма — возможность легко и беспрепятственно разделять между ними данные, поэтому, уже зная, как создавать потоки и управлять ими, мы обратимся к вопросам, связанным с разделением данных.

Представьте, что вы живете в одной квартире с приятелем. В квартире только одна кухня и только одна ванная. Если ваши отношения не особенно близки, то вряд ли вы будете пользоваться ванной одновременно, поэтому, когда сосед слишком долго занимает ванную, у вас возникает законное недовольство. Готовить два блюда одновременно, конечно, можно, но если у вас духовка совмещена с грилем, то ничего хорошего не выйдет, когда один пытается жарить сосиски, а другой — печь пирожные. Ну и все мы знаем, какую досаду испытываешь, когда, сделав половину работы, обнаруживаешь, что кто-то забрал нужный инструмент или изменил то, что вы уже сделали.

То же самое и с потоками. Если потоки разделяют какие-то данные, то необходимы правила, регулирующие, какой поток в какой момент к каким данным может обращаться и как сообщить об изменениях другим потокам, использующим те же данные. Легкость, с которой можно разделять данные между потоками в одном процессе, может обернуться не только благословением, но проклятием. Некорректное использование разделяемых данных — одна из основных причин ошибок, связанных с параллелизмом, и последствия могут оказаться куда серьезнее, чем пропахшие сосисками пирожные.

Эта глава посвящена вопросу о том, как безопасно разделять данные между потоками в программе на С++, чтобы избежать возможных проблем и достичь оптимального результата.

3.1. Проблемы разделения данных между потоками

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


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

Это знаменитый бестселлер, который научит вас использовать власть массового сотрудничества и покажет, как применять викиномику в вашем бизнесе. Переведенная более чем на двадцать языков и неоднократно номинированная на звание лучшей бизнес-книги, "Викиномика" стала обязательным чтением для деловых людей во всем мире. Она разъясняет, как массовое сотрудничество происходит не только на сайтах 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 так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.