Иллюстрированный самоучитель по Architecture .NET

Модель приложений .NET. Потоки.

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

Рассмотрим несколько участков в коде, где происходит заказ места в гостинице и там, где происходит резервирование свободных мест – именно в этих точках могут возникнуть трудности подобного рода. Исследуем код для Broker::Reserve (Брокер::Резерв) в Broker.h. Сначала сделаем проверку существующих заказов для данной гостиницы и для данной даты, чтобы узнать, есть ли свободные номера. Тогда, если есть в наличии свободный номер, он резервируется. Мы добавили вызов метода Thread::Sleep (Поток-Режим ожидания) между кодом, который проверяет имеющиеся в распоряжении номера и кодом, который резервирует свободный номер. Вскоре будет объяснено, для чего это было сделано.

// Проверить, есть ли номера для всех дат
for (int i = day; i < day + numDays; i++)
{
if (numCust[i, unitid] >= unit › capacity)
{
result › Reservation!d = -1; // результат
result › Comment = "Room not available";
// результат › Комментарий = "Номера не доступны";
return result; // результат
}
}
Console::WriteLine(
"Thread {0} finds the room is available in
Broker::Reserve",
// "Поток {0} находит, что номер доступен в
// Брокер:: Резерв ",
Thread::CurrentThread › // Поток GetHashCode{).ToString());
Thread::Sleep(0); // Поток:: Бездействие
// Резервировать номер для требуемых дат
for (int i = day; i < day + numDays; i++)
numCust[i, unitid] += 1;

Этот код может привести к противоречивым результатам! Один из потоков может быть прерван сразу после того, как обнаружит последний имеющийся в распоряжении номер, но прежде, чем он получит шанс сделать заказ. Другой поток, которому предоставляется отрезок процессорного времени, может найти тот же самый доступный номер гостиницы и сделать заказ. Когда первый поток запускается снова, он начинает работу с точки, где был прерван, и также закажет тот же самый последний номер в гостинице.

Чтобы смоделировать возникновение такой ситуации, на этом шаге (шаг 1) примера Threading (Организация поточной обработки) поместим вызов метода Thread::Sleep (Поток::Режим ожидания) между кодом, который проверяет имеющиеся в распоряжении номера и кодом, который резервирует свободный номер. Вызов Sleep (0) заставляет поток прекратить выполнение и уступить остаток своего временного отрезка.

Чтобы удостовериться в том, что мы наблюдаем именно возникновение проблемы соперничества между потоками, мы имеем в своем распоряжении всего один номер в целой гостинице! Затем мы подготавливаем нашу программу так, чтобы два потока пробовали резервировать единственный номер в гостинице на ту же самую дату. Рассмотрим код в подпрограмме Main (Главная), который все это подготавливает:

hotelBroker › AddHotel(
"Boston", // "Бостон",
"Presidential", // "Президентская",
1, // только один номер во всей гостинице!
(Decimal) 10000); // (Десятичное число)
NewReservation *reservel =
new NewReservation(customers, hotelBroker); // клиенты
reservel › customerld = 1;
reservel › city = "Boston"; // город = "Бостон";
reservel › hotel = "Presidential"; // гостиница = "Президентская";
reservel › sdate = "12/12/2001";
reservel › numberDays = 3;
NewReservation *reserve2 =
new NewReservation(customers, hotelBroker); // клиенты
reserve2 › customerld = 2;
reserve2 › city = "Boston"; // город = "Бостон";
reserve2 › hotel = "Presidential"; // гостиница = "Президентская";
reserve2 › sdate = "12/13/2001";
reserve2 › numberDays = 1;
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.