В ситуации на картинке три трамвая захватили по одному ресурсу (перекрестку) и пытаются захватить еще один, что, очевидно, невозможно без освобождения уже захваченных. В жизни ситуация разрешилась просто - самый молодой из водителей был вынужден отъехать. В информационных технологиях все бывает сложнее. Откройте любой документ, сопровождающий очередной пакет обновления к любой версии Windows. Очень часто там можно найти информацию об одной-двух исправленных ситуациях тупиков.

Гонки

Ситуация гонок возникает, когда два или более потока пытаются получить доступ к общему ресурсу и изменить его состояние. Рассмотрим следующий пример. Пусть Поток 1 получил доступ к ресурсу и изменил его в своих интересах; затем активизировался Поток 2 и модифицировал этот же ресурс до завершения Потока 1. Поток 1 полагает, что ресурс остался в том же состоянии, в каком был до переключения. В зависимости от того, когда именно был изменен ресурс, результаты могут варьироваться - иногда код будет выполняться нормально, иногда нет. Программисты не должны строить никаких гипотез относительно порядка исполнения потоков, т. к. планировщик ОС может запускать и останавливать их в любое время.

Inc(i);
if i = iSomething then DoSomething;

Здесь i - глобальная переменная, доступная из обоих потоков. Пусть два или более потоков исполняют этот код одновременно. Поток 1 инкремен-тировал значение переменной i и хочет проверить ее значение для выполнения тех или иных условий. Но тут активизируется другой поток, который еще увеличивает значение i. В результате первый поток "проскакивает" мимо условия, которое, казалось бы, должно было быть выполнено.

Возникновения как ситуаций гонок, так и тупиков можно избежать, если использовать приемы, обсуждаемые ниже.

Средства синхронизации потоков

Проще всего говорить о синхронизации, если создаваемый поток не взаимодействует с ресурсами других потоков и не обращается к VCL. Допустим, у вас на компьютере несколько процессоров, и вы хотите "распараллелить" вычисления. Тогда вполне уместен следующий код:

MyCompThread := TComputationThread.Create(False);
// Здесь можно что-нибудь делать, пока второй поток производит вычисления DoSomeWork;
/ / Теперь ожидаем его завершения MyCompThread.WaitFor;

Приведенная схема совершенно недопустима, если во время своей работы ПОТОК MyCompThread обращается К VCL посредством метода Synchronize. В этом случае поток ждет главный поток для обращения к VCL, а тот, в свою очередь, его - классический тупик.

За "спасением" следует обратиться к программному интерфейсу Win32. Он предоставляет богатый набор инструментов, которые могут понадобиться для организации совместной работы потоков.

Главные понятия для понимания механизмов синхронизации - функции ожидания и объекты синхронизации. В Windows API предусмотрен ряд функций, позволяющих приостановить выполнение вызвавшего эту функцию потока вплоть до того момента, как будет изменено состояние какого-то объекта, называемого объектом синхронизации (под этим термином здесь понимается не объект Delphi, а объект операционной системы). Простейшая из этих функций - waitForSingleobject - предназначена для ожидания одного объекта.


⇐ Предыдущая страница| |Следующая страница ⇒

Программирование в Delphi 7



Новости за месяц

  • Ноябрь
    2017
  • Пн
  • Вт
  • Ср
  • Чт
  • Пт
  • Сб
  • Вс