Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - [120]

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

Такие оптимизации корректны, только если память ведет себя нормально. “Особая” память так себя не ведет. Наиболее распространенным видом особой памяти, вероятно, является память, используемая для отображенного на память ввода-вывода.. Вместо чтения и записи обычной памяти, местоположения в такой особой памяти в действительности сообщаются с периферийными устройствами, например внешними датчиками или мониторами, принтерами, сетевыми портами и т.п. Давайте с учетом этого снова рассмотрим код с, казалось бы, избыточными чтениями:

>auto y = x; // Чтение x

>y = x;      // Чтение x еще раз

Если >x соответствует, скажем, значению, которое передает датчик температуры, то второе чтение >x избыточным не является, поскольку температура между первым и вторым чтениями может измениться.

Похожа ситуация с записями, кажущимися излишними. Например, если в коде

>x = 10; // Запись x

>х = 20; // Запись x еще раз

переменная x соответствует управляющему порту радиопередатчика, может оказаться, что этот код выполняет некоторые команды с радиопередатчиком, и значение 10 соответствует команде, отличной от имеющей код 20. Оптимизация, убирающая первое присваивание, могла бы изменить последовательность команд, отправляемых радиопередатчику.

Квалификатор >volatile представляет собой способ сообщить компиляторам, что мы имеем дело с такой особой памятью. Для компилятора это означает “не выполняй никаких оптимизаций над операциями с этой памятью”. Так что если переменная >x соответствует особой памяти, она должна быть объявлена как >volatile:

>volatile int x;

Рассмотрим влияние этого квалификатора на последовательность нашего исходного кода:

>auto y = x; // Чтение x

>y = x;      // Чтение x еще раз (не может быть устранено)

>x = 10;     // Запись x (не может быть устранена)

>x = 20;     // Запись x еще раз

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

Вопрос на засыпку: какой тип у в последнем фрагменте кода: >int или >volatile int[28]?

Тот факт, что кажущиеся избыточными загрузки и бессмысленные сохранения должны оставаться на месте при работе с особой памятью, объясняет, кстати, почему для такого рода работы не подходят объекты >std::atomic. Компиляторам разрешается устранять такие избыточные операции у >std::atomic. Код написан не в точности так же, как и для >volatile, но если мы на минуту отвлечемся от этого и сосредоточимся на том, что компиляторам разрешается делать, то можно сказать, что концептуально компиляторы могут, получив код

>std::atomic<int> x;

>auto y = x; // Концептуально читает x (см. ниже)

>y = x;      // Концептуально читает x еще раз (см. ниже)

>x = 10;     // Записывает x

>х = 20;     // Записывает x еще раз

оптимизировать его до

>auto y = x; // Концептуально читает x (см. ниже)

>x = 20;     // Записывает x

Очевидно, что это неприемлемое поведение при работе с особой памятью.

Но если >x имеет тип >std::atomic, ни одна из этих инструкций компилироваться не будет:

>auto y = x; // Ошибка!

>y = x;      // Ошибка!

Дело в том, что копирующие операции в >std::atomic удалены (см. раздел 3.5). И не зря. Рассмотрим, что произошло бы, если бы инициализация у значением x компилировалась. Поскольку >x имеет тип >std::atomic, тип у был бы также выведен как >std::atomic (см. раздел 1.2). Ранее я отмечал, что одна из лучших возможностей >std::atomic заключается в атомарности всех их операций, но чтобы копирующее конструирование >y из >x было атомарным, компиляторы должны генерировать код для чтения >x и записи >y как единую атомарную операцию. В общем случае аппаратное обеспечение не в состоянии это сделать, так что копирующее конструирование типами >std::atomic не поддерживается. Копирующее присваивание удалено по той же причине, а потому присваивание >x переменной >y также не компилируется. (Перемещающие операции не объявлены в >std::atomic явно, так что в соответствии с правилами генерации специальных функций, описанных в разделе 3.11, >std::atomic не предоставляет ни перемещающего конструирования, ни перемещающего присваивания.)

Можно получить значение >x в переменную >y, но это требует использования функций- членов >load и >store типа >std::atomic. Функция-член >load атомарно считывает значение >std::atomic, а функция-член >store атомарно его записывает. Для инициализации >y значением >x, после которой выполняется размещение значения >x в >y, код должен иметь следующий вид:

>std::atomic y(x.load()); // Чтение x

>y.store(x.load());            // Чтение x еще раз

Этот код компилируется, но тот факт, что чтение >x (с помощью >x.load()) является отдельным от инициализации или сохранения значения вызовом функции, делает очевидным то, что нет никаких оснований ожидать, что целая инструкция будет выполняться как единая атомарная операция.

Компиляторы могут “оптимизировать” приведенный код, сохраняя значение >x в регистре вместо двойного его чтения:

>register = x.load();          // Чтение x в регистр


>std::atomic y(register); // Инициализация y

>                              // значением регистра

>y.store(


Еще от автора Скотт Мейерс
Эффективное использование STL

В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


Как функции, не являющиеся методами, улучшают инкапсуляцию

Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Платформа J2Me

Эта книга научит вас, как разрабатывать программное обеспечение для платформы J2ME компании «Sun Microsystems». Эта книга придерживается стиля учебного пособия, это не справочное руководство.Цель — дать вам твердую основу в понятиях и техниках, которая даст вам возможность решиться на самостоятельную разработку качественных приложений.


Виртуальная библиотека Delphi

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


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

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


Программное обеспечение встроенных систем. Общие требования к разработке и документированию

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.