|
Выше мы
рассмотрели, как потоки одного процесса могут
вступить в конфликт и испортить работу друг
друга. Одной из задач программиста является
обеспечить невозможность такого сценария.
Другими возможными неприятностями могут быть:
рассинхронизация (race conditions) и
тупиковая ситуация
(deadlock).
Первая может произойти, когда успех одной
операции зависит от успеха другой, но обе они не
синхронизированы друг с другом. Предположим, что
один поток процесса подготавливает принтер, а
другой ставит задание на печать (print job)
в очередь. Если потоки не синхронизированы и
первый из них не успеет выполнить свою работу до
того, как начнется печать, то мы получим сбой.
Примечание
Но в каком-то
количестве случаев все пройдет гладко. Такой тип
ошибок очень неприятен, так как в процессе
отладки ее нельзя уверенно и многократно
воспроизводить. Рассинхронизация порождает
ненадежность —тип ошибок, который большинство
программистов всего мира ненавидит. В MSDN, но,
к сожалению, не в литературе, вы часто можете
встретить упоминания о коварстве irreprodudble
bugs (невоспроизводимые ошибки). Суверенностью
можно сказать, что книга под названием
«Технологии борьбы с ошибками» была бы
бестселлером.
Тупиковая ситуация создается, когда один поток
ждет завершения второго, а второй ждет
завершения первого. Представьте, что один поток
реализует такую функцию:
-
блокирует запись, идентифицирующую клиента;
-
блокирует запись, описывающую его счет;
-
изменяет обе записи;
-
освобождает запись, описывающую счет;
-
освобождает запись, идентифицирующую
клиента.
Обратите внимание
на то, что освобождение блокировок происходит в
обратном порядке. Именно так следует поступать
при работе с записями базы данных и всеми
объектами ядра Windows. Предположим далее, что
второй поток реализует функцию начисления
месячного процента и он делает те же действия,
что и первый, но порядок блокирования и
освобождения записей обратный. Оба потока по
отдельности функционируют вполне надежно. В
процессе работы возможен следующий сценарий:
первый поток блокирует запись, идентифицирующую
клиента, затем второй блокирует запись,
описывающую его счет. После этого оба ждут
освобождения записей, блокированных друг другом.
Если ожидание реализовано разработчиком в виде
бесконечного цикла, то мы его получили. Это
тупиковая ситуация, или
deadlock. |