Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - [111]
>std::thread
, может безопасно к ним обращаться.• ThreadRAII предоставляет функцию >get
, обеспечивающую доступ к соответствующему объекту >std::thread
. Это аналог функций >get
, предоставляемых стандартными интеллектуальными указателями и обеспечивающих доступ к их базовым обычным указателям. Предоставление >get
позволяет избежать необходимости дублировать в классе ThreadRAII весь интерфейс >std::thread
, а также означает, что объекты ThreadRAII могут использоваться в контекстах, где требуются объекты >std::thread
.
• Перед тем как деструктор ThreadRAII вызовет функцию-член объекта t типа >std::thread
, он проверяет, является ли этот объект подключаемым. Это необходимо, поскольку применение >join
или >detach
к неподключаемому объекту приводит к неопределенному поведению. Может быть так, что клиент создает >std:: thread
, затем создает из него объект ThreadRAII, использует функцию-член >get
для получения доступа к >t
, а затем выполняет перемещение из >t
или вызывает для него >join
или >detach
. Каждое из этих действий делает >t
неподключаемым.
>if (t.joinable()) {
> if (action == DtorAction::join) {
> t.join();
> } else {
> t.detach();
> }
>}
Если в приведенном фрагменте вас беспокоит возможность условия гонки из-за того, что между вызовами >t.joinable()
и >join
или >detach
другой поток может сделать >t
неподключаемым, то ваша интуиция заслуживает похвалы, но ваши опасения в данном случае беспочвенны. Объект >std::thread
может изменить состояние с подключаемого на неподключаемое только путем вызова функции-члена, например >join
, >detach
или операции перемещения. В момент вызова деструктора ThreadRAII никакие другие потоки не должны вызывать функцию-член для этого объекта. При наличии одновременных вызовов, определенно, имеется условие гонки, но не внутри деструктора, а в клиентском коде, который пытается вызвать одновременно две функции-члена объекта (деструктор и что-то еще). В общем случае одновременные вызовы функций-членов для одного объекта безопасны, только если все они являются константными функциями-членами (см. раздел 3.10).
Использование >ThreadRAII
в нашей функции >doWork
может выглядеть следующим образом:
>bool doWork(std::function
> int maxVal = tenMillion)
>{
> std::vector
> ThreadRAII t( // use RAII object
> std::thread([&filter, maxVal, &goodVals] {
> for (auto i = 0; i <= maxVal; ++i)
> { if (filter(i)) goodVals.push_back(i); }
> }),
> ThreaRAII::DtorAction::join // Действие RAII
> );
> auto nh = t.get().native_handle();
> …
> if (conditionsAreSatisfied()) {
> t.get().join();
> performComputation(goodVals);
> return true;
> }
> return false;
>}
В этом случае мы выбрали использование >join
для асинхронно выполняющегося потока в деструкторе >ThreadRAII
, поскольку, как мы видели ранее, применение >detach
может привести к настоящим кошмарам при отладке. Мы также видели ранее, что применение >join
может вести к аномалиям производительности (что, откровенно говоря, также может быть неприятно при отладке), но выбор между неопределенным поведением (к которому ведет >detach
), завершением программы (при использовании обычного >std::thread
) и аномалиями производительности предопределен — мы выбираем меньшее из зол.
Увы, раздел 7.5 демонстрирует, что применение >ThreadRAII
для выполнения >join
при уничтожении >std::thread
иногда может привести не к аномалии производительности, а к полному “зависанию” программы. “Правильным” решением этого типа проблем было бы сообщить асинхронно выполняющемуся лямбда-выражению, что в его услугах мы больше не нуждаемся и оно должно поскорее завершиться. Увы, С++11 не поддерживает прерываемые потоки. Их можно реализовать вручную, но данный вопрос выходит за рамки нашей книги[24].
В разделе 3.11 поясняется, что, поскольку >ThreadRAII
объявляет деструктор, в нем нет генерируемых компилятором перемещающих операций, но причин, по которым >ThreadRAII
не должен быть перемещаемым, тоже нет. Если бы компилятор генерировал такие функции, то они демонстрировали бы верное поведение, так что просто попросим компилятор их все же сгенерировать:
>class ThreadRAII {
>public:
> enum class DtorAction { join, detach }; // Как и ранее
> ThreadRAII(std::thread&& t, DtorAction a) // Как и ранее
> : action(а), t(std::move(t)) {}
> ~ThreadRAII() {
> … // Как и ранее
> }
> ThreadRAII(ThreadRAII&&) = default; // Поддержка
> ThreadRAII& operator=(ThreadRAII&&) = default; // перемещения
> std::threads get() { return t; } // Как и ранее
>private: // Как и ранее
> DtorAction action;
> std::thread t;
>};
• Делайте >std::thread
неподключаемыми на всех путях выполнения.
• Применение >join
при уничтожении объекта может привести к трудно отлаживаемым аномалиям производительности.
В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.
Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.