Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - [30]
>hierarchical_mutex
, где его защищает захваченный внутренний мьютекс.Функция >try_lock()
работает так же, как >lock()
, с одним отличием — если вызов >try_lock()
для >internal_mutex
завершается ошибкой (7), то мы не владеем мьютексом и, следовательно, не изменяем уровень иерархии, а вместо >true
возвращаем >false
.
Все проверки производятся на этапе выполнения, но, по крайней мере, они не зависят от времени — нет нужды дожидаться, пока сложатся редкие условия, при которых возникает взаимоблокировка. Кроме того, ход мыслей проектировщика, направленный на подобное отделение логики приложения от мьютексов, помогает предотвратить многие возможные причины взаимоблокировок еще до того, как они прокрадутся в код. Такое мысленное упражнение полезно проделать даже в том случае, когда проектировщик не собирается фактически кодировать проверки во время выполнения.
Я уже упоминал в начале этого раздела, что взаимоблокировка может возникать не только вследствие захвата мьютекса, а вообще в любой конструкции синхронизации, сопровождающейся циклом ожидания. Поэтому стоит обобщить приведенные выше рекомендации и на такие случаи. Например, мы говорили, что следует по возможности избегать вложенных блокировок, и точно так же не рекомендуется ждать поток, удерживая мьютекс, потому что этому потоку может потребоваться тот же самый мьютекс для продолжения работы. Аналогично, если вы собираетесь ждать завершения потока, то будет разумно определить иерархию потоков, так чтобы любой поток мог ждать только завершения потоков, находящихся ниже него в иерархии. Простой способ реализовать эту идею — сделать так, чтобы присоединение потоков происходило в той же функции, которая их запускала (как описано в разделах 3.1.2 и 3.3).
Функция >std::lock()
и шаблон класса >std::lock_guard
покрывают большую часть простых случаев блокировки, по иногда этого недостаточно. Поэтому в стандартную библиотеку включен также шаблон >std::unique_lock
. Подобно >std::lock_guard
, этот шаблон класса параметризован типом мьютекса и реализует такое же управление блокировками в духе RAII, что и >std::lock_guard
, однако обладает чуть большей гибкостью.
3.2.6. Гибкая блокировка с помощью >std::unique_lock
Шаблон >std::unique_lock
обладает большей гибкостью, чем >std::lock_guard
, потому что несколько ослабляет инварианты — экземпляр >std::unique_lock
не обязан владеть ассоциированным с ним мьютексом. Прежде всего, в качестве второго аргумента конструктору можно передавать не только объект >std::adopt_lock
, заставляющий объект управлять захватом мьютекса, но и объект >std::defer_lock
, означающий, что в момент конструирования мьютекс не должен захватываться. Захватить его можно будет позже, вызвав функцию-член >lock()
объекта >std::unique_lock
(а не самого мьютекса) или передав функции >std::lock()
сам объект >std::unique_lock
. Код в листинге 3.6 можно было бы с тем же успехом написать, как показало в листинге 3.9, с применением >std::unique_lock
и >std::defer_lock()
(1) вместо >std::lock_guard
и >std::adopt_lock
. В новом варианте столько же строк, и он эквивалентен исходному во всем, кроме одной детали, — >std::unique_lock
потребляет больше памяти и выполняется чуть дольше, чем >std::lock_guard
. Та гибкость, которую мы получаем, разрешая экземпляру >std::unique_lock
не владеть мьютексом, обходится не бесплатно — дополнительную информацию надо где-то хранить и обновлять.
Листинг 3.9. Применение >std::lock()
и >std::unique_guard
для реализации операции обмена
>class some_big_object;
>void swap(some_big_object& lhs,some_big_object& rhs);
>class X {
>private:
> some_big_object some_detail;
> std::mutex m;
>public:
> X(some_big_object const& sd): some_detail(sd) {}
> friend void swap(X& lhs, X& rhs) {
> if (&lhs == &rhs)
std::defer_lock оставляет
> return;
мьютексы не захваченными (1)
> std::unique_lock
> std::unique_lock
> std::lock(lock_a, lock_b); ←
(2) Мьютексы захватываются
> swap(lhs.some_detail, rhs.some_detail);
> }
>};
В листинге 3.9 объекты >std::unique_lock
можно передавать функции >std::lock()
(2), потому что в классе >std::unique_lock
имеются функции-члены >lock()
, >try_lock()
и >unlock()
. Для выполнения реальной работы они вызывают одноименные функции контролируемого мьютекса, а сами только поднимают в экземпляре >std::unique_lock
флаг, показывающий, что в данный момент этот экземпляр владеет мьютексом. Флаг необходим для того, чтобы деструктор знал, вызывать ли функцию >unlock()
. Если экземпляр действительно владеет мьютексом, то деструктор должен вызвать >unlock()
, в противном случае — не должен. Опросить состояние флага позволяет функция-член >owns_lock()
.
Естественно, этот флаг необходимо где-то хранить. Поэтому размер объекта >std::unique_lock
обычно больше, чем объекта >std::lock_guard
, и работает >std::unique_lock
Это знаменитый бестселлер, который научит вас использовать власть массового сотрудничества и покажет, как применять викиномику в вашем бизнесе. Переведенная более чем на двадцать языков и неоднократно номинированная на звание лучшей бизнес-книги, "Викиномика" стала обязательным чтением для деловых людей во всем мире. Она разъясняет, как массовое сотрудничество происходит не только на сайтах 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 так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.