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

Здесь фундаментальная проблема заключается в том, что мы не сделали того, что собирались сделать: пометить все участки кода, в которых имеется доступ к структуре данных, как взаимно исключающие. В данном случае мы забыли о коде внутри foo(), который вызывает unprotected->do_something(). К сожалению, в этом стандартная библиотека С++ нам помочь не в силах: именно программист должен позаботиться о том, чтобы защитить данные мьютексом. Но не всё так мрачно — следование приведенной ниже рекомендации выручит в таких ситуациях. Не передавайте указатели и ссылки на защищенные данные за пределы области видимости блокировки никаким способом, будь то возврат из функции, сохранение в видимой извне памяти или передача в виде аргумента пользовательской функции.

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

<p>3.2.3. Выявление состояний гонки, внутренне присущих интерфейсам</p>

Тот факт, что вы пользуетесь мьютексами или другим механизмом для защиты разделяемых данных, еще не означает, что гонок можно не опасаться, — следить за тем, чтобы данные были защищены, все равно нужно. Вернемся снова к примеру двусвязного списка. Чтобы поток мог безопасно удалить узел, необходимо предотвратить одновременный доступ к трем узлам: удаляемому и двум узлам но обе стороны от него. Заблокировав одновременный доступ к указателям на каждый узел но отдельности, мы не достигнем ничего по сравнению с вариантом, где мьютексы вообще не используются, поскольку гонка по-прежнему возможна. Защищать нужно не отдельные узлы на каждом шаге, а структуру данных в целом на все время выполнения операции удаления. Простейшее решение в данном случае — завести один мьютекс, который будет защищать весь список, как в листинге 3.1.

Однако и после обеспечения безопасности отдельных операций наши неприятности еще не закончились — гонки все еще возможны, даже для самого простого интерфейса. Рассмотрим структуру данных для реализации стека, например, адаптер контейнера std::stack, показанный в листинге 3.3. Помимо конструкторов и функции swap(), имеется еще пять операций со стеком: push() заталкивает в стек новый элемент, pop() выталкивает элемент из стека, top() возвращает элемент, находящийся на вершине стека, empty() проверяет, пуст ли стек, и size() возвращает размер стека. Если изменить top(), так чтобы она возвращала копию, а не ссылку (в соответствии с рекомендацией из раздела 3.2.2), и защитить внутренние данные мьютексом, то и тогда интерфейс уязвим для гонки. Проблема не в реализации на основе мьютексов, она присуща самому интерфейсу, то есть гонка может возникать даже в реализации без блокировок.

Листинг 3.3. Интерфейс адаптера контейнера std::stack

template >

class stack {

public:

 explicit stack(const Container&);

 explicit stack(Container&& = Container());

 template explicit stack(const Alloc&);

 template stack(const Container&, const Alloc&);

 template stack(Container&&, const Alloc&);

 template stack(stack&&, const Alloc&);

 bool empty() const;

 size_t size() const;

 T& top();

 T const& top() const;

 void push(T const&);

 void push(T&&);

 void pop();

 void swap(stack&&);

};

Проблема в том, что на результаты, возвращенные функциями empty() и size(), нельзя полагаться — хотя в момент вызова они, возможно, и были правильны, но после возврата из функции любой другой поток может обратиться к стеку и затолкнуть в него новые элементы, либо вытолкнуть существующие, причем это может произойти до того, как у потока, вызвавшего empty() или size(), появится шанс воспользоваться полученной информацией.

Если экземпляр stack не является разделяемым, то нет ничего страшного в том, чтобы проверить, пуст ли стек с помощью empty(), а затем, если стек не пуст, вызвать top() для доступа к элементу на вершине стека:

stack s;

if (!s.empty())             ←(1)

{

 int const value = s.top(); ←(2)

 s.pop();                   ←(3)

 do_something(value);

}

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

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

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

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

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

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

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

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

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