Главная опасность (общие данные)
Результат показан на рис. 10.6: температура в доме достигла 105 градусов по Фаренгейту (40.5 градуса по Цельсию)!
Рис. 10.6. Проблемы многопоточности
В процедуре Sub Main (строки 4-7) создается "дом" с десятью "комнатами". Класс House устанавливает максимальную температуру 75 градусов по Фаренгейту (около 24 градусов по Цельсию). В строках 13-28 определяется довольно сложный конструктор дома. Ключевыми для понимания программы являются строки 18-27. Строка 20 создает очередной объект комнаты, при этом конструктору передается ссылка на объект дома, чтобы объект комнаты при необходимости мог к нему обратиться.
Строки 21-23 запускают десять потоков для регулировки температуры в каждой комнате. Класс Room определяется в строках 38-73. Ссылка на объект House coxpaняется в переменной mHouse в конструкторе класса Room (строка 43). Код проверки и регулировки температуры (строки 50-66) выглядит просто и естественно, но как вы вскоре убедитесь, это впечатление обманчиво! Обратите внимание на то, что этот код заключен в блок Try-Catch, поскольку в программе используется метод Sleep.
Вряд ли кто-нибудь согласится жить при температуре в 105 градусов по Фаренгейту (40.5 градусов по Цельсию). Что же произошло? Проблема связана со следующей строкой:
If mHouse.HouseTemp < mHouse.MAX_TEMP -5 Then
А происходит следующее: сначала температуру проверяет поток 1. Он видит, что температура слишком низка, и поднимает ее на 5 градусов. К сожалению, перед повышением температуры поток 1 прерывается и управление передается поток 2. Поток 2 проверяет ту же самую переменную, которая еще не была изменена потоком 1. Таким образом, поток 2 тоже готовится поднять температуру на 5 градусов, но сделать этого не успевает и тоже переходит в состояние ожидания.
Процесс продолжается до тех пор, пока поток 1 не активизируется и не перейдет к следующей команде – повышению температуры на 5 градусов. Повышение повторяется при активизации всех 10 потоков, и жильцам дома придется плохо.