|
Материалы книги получены с http://www.itlibitum.ru/
Взаимные блокировки и очереди
Если в любой момент времени может существовать не более одной транзакции, все замечательно. Если же с вашими объектами могут возиться сразу несколько транзакций, придется сделать еще несколько шагов. Возможны разные причины - например, ваше приложение-сервер может обслуживать несколько пользователей, или вы напишете графическое приложение с контекстной отменой, в котором необходимо запоминать отменяемую команду для нескольких окон. Наконец, остается еще одно препятствие - необходимо продумать поведение вашей программы в ситуации, когда она пытается заблокировать уже заблокированный объект.
Консервативная блокировка
При консервативной блокировке (conservative locking) транзакция блокирует все объекты, которые ей могут понадобиться, до внесения каких-либо изменений. Если заблокировать все объекты не удается, транзакция либо ждет, пока они станут доступными, либо поднимает руки и сообщает пользователю, что при всем уважении к нему просьба отклоняется. Одна из возможных реализаций консервативной блокировки заключается в том, чтобы субклассировать Transaction и попытаться заблокировать все необходимое в конструкторе производного класса (при наличии стандартной обработки исключений) или в его отдельной инициализирующей функции (при отсутствии такой обработки).
Агрессивная блокировка
При агрессивной блокировке (aggressive locking) транзакция может начинаться в любой момент и блокировать объекты по мере необходимости. Я бы назвал ее «своевременной» блокировкой, поскольку блокируются только непосредственно обновляемые объекты и это происходит перед первым обновлением.
Очереди и взаимные блокировки
Вопрос о том, стоит ли создавать очереди запросов на блокировку, составляет отдельный аспект дизайна. Если очереди не поддерживаются и транзакция попытается заблокировать объект, ранее заблокированный другой транзакцией, она заканчивается неудачей. При консервативной блокировке транзакция вообще не начинается, а при аггрессивной она возвращается к прежнему состоянию, скрещивает руки на своей двоичной груди и сурово смотрит на пользователя. В некоторых приложениях это вполне нормально, но в действительности это решение из тех, о которых специалисты из службы поддержки могут лишь мечтать - ведь оно гарантирует им постоянную работу. Чтобы не отказываться от второй транзакции, обычно стоит подождать снятия блокировки с объекта текущей
транзакцией.
При отсутствии очередей вам не придется беспокоиться о ситуациях взаимной блокировки (когда A ожидает B, а B ожидает A). Если транзакция запросила блокировку и не смогла ее получить, она уничтожается. Если очереди поддерживаются, код блокировки должен определить, принадлежит ли этой транзакции какие-либо блокировки, которых дожидаются остальные, и если принадлежат, избавить одну из транзакций от бескенечного ожидания.
Происходящее оказывается в опасной близости от точки, в которой вам приходится либо разбивать свое приложение на несколько подзадач и поручать операционной системе их планирование, либо воспользоваться одной из коммерческих библиотек с поддержкой многопоточности. Так или иначе, в этой области мы не узнаем ничего принципиально нового, относящегося к С++, и поэтому не будем развивать эту тему. Об очередях, блокировках и многопоточности написано немало хороших книг, вы наверняка найдете их в разделе «Базы данных» своего книжного магазина.
Назад Содержание Далее
|