Читаем Параллельное программирование на С++ в действии полностью

Шаблон 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 lock_a(lhs.m, std::defer_lock);←┤

   std::unique_lock lock_b(rhs.m, std::defer_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 чуть медленнее std::lock_guard, потому что флаг нужно проверять и обновлять. Если класс std::lock_guard отвечает вашим нуждам, то я рекомендую использовать его. Тем не менее, существуют ситуации, когда std::unique_lock лучше отвечает поставленной задаче, так как без свойственной ему дополнительной гибкости не обойтись. Один из примеров — показанный выше отложенный захват; другой — необходимость передавать владение мьютексом из одного контекста в другой.

<p>3.2.7. Передача владения мьютексом между контекстами</p>

Поскольку экземпляры std::unique_lock не владеют ассоциированными мьютексами, то можно передавать владение от одного объекта другому путем перемещения. В некоторых случаях передача производится автоматически, например при возврате объекта из функции, а иногда это приходится делать явно, вызывая std::move(). Ситуация зависит от того, является ли источник l-значением — именованной переменной или ссылкой на нее — или r-значением — временным объектом. Если источник — r-значение, то передача владения происходит автоматически, в случае же l-значение это нужно делать явно, чтобы не получилось так, что переменная потеряет владение непреднамеренно. Класс std::unique_lock дает пример перемещаемого, но не копируемого типа. Дополнительные сведения о семантике перемещения см. в разделе А.1.1 приложения А.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных