Стандарты программирования на С++. 101 правило и рекомендация | страница 28



• Проектирование, не требующее блокировок, включая неизменяемость (объекты, предназначенные только для чтения). Можно разработать типы, для которых блокировка окажется полностью ненужной (см. ссылки). Одним из распространенных примеров являются неизменяемые объекты, которые не требуют блокировки, поскольку они никогда не изменяются. Например, будучи создан, объект неизменяемого строкового типа больше не модифицируется, а все строковые операции приводят к созданию новых строк.

Заметим, что вызывающий код ничего не должен знать о деталях реализации ваших типов (см. рекомендацию 11). Если ваш тип внутренне использует какие-то методики разделения данных (например, копирование при записи), вы не должны нести ответственность за все возможные вопросы безопасности потоков, но обязаны обеспечить корректность работы вызывающего кода при обычной работе — т.е. тип должен быть безопасен в плане многопоточности в той же мере, как если бы он не использовал методики совместного использования данных (см. [Sutter04c]). Как упоминалось, все корректно написанные типы должны позволять работу с различными объектами в разных потоках без синхронизации.

В частности, если вы разрабатываете библиотеку, предназначенную для широкого использования, вы должны предусмотреть безопасность ваших объектов в многопоточных программах, как описано выше, но при этом без дополнительных накладных расходов при работе в однопоточной программе. Например, если вы пишете библиотеку, содержащую тип, использующий копирование при записи, и вы должны обеспечить, как минимум, некоторую внутреннюю блокировку, то предпочтительно разработать ее так, чтобы в однопоточном варианте вашей библиотеки ее не было (обычно для этого используются директивы препроцессора >#ifdef).

Если используется несколько блокировок, то избежать взаимоблокировки можно путем их запроса в одинаковом порядке (освобождение блокировок может выполняться в любом порядке). Одно из решений состоит в запросе блокировок в порядке возрастания адресов в памяти, что обеспечивает удобное, однозначное упорядочение в пределах приложения.

Ссылки

[Alexandrescu02a] • [Alexandrescu04] • [Butenhof97] • [Henney00] • [Henney01] • [Meyers04] • [Schmidt01] • [Stroustrup00] §14.9 • [Sutter02] §16 • [Sutter04c]

13. Ресурсы должны быть во владении объектов

Резюме

Не работайте вручную, если у вас есть мощные инструменты. Идиома С++ "выделение ресурса есть инициализация" (resource acquisition is initialization — RAII) представляет собой мощный инструмент для корректной работы с ресурсами. RAII позволяет компилятору автоматически обеспечить строгую гарантию того, что в других языках надо делать вручную. При выделении ресурса передайте его объекту-владельцу. Никогда не выделяйте несколько ресурсов в одной инструкции.