Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Критические секции






Работают они следующим образом: внутри критической секции может работать только один поток, другие ждут его завершения. Чтобы лучше понять, везде приводят сравнение с узкой трубой: представьте, с одной стороны " толпятся" потоки, но в трубу может " пролезть" только один, а когда он " пролезет" - начнёт движение второй, и так по порядку. Еще проще понять это на примере и тем же ProgressBar'ом. Итак, запустите один из примеров, приведённых ранее. Нажмите на кнопку, подождите несколько секунд, а затем нажмите еще раз. Что происходит? ProgressBar начал прыгать. Прыгает потому, что у нас работает не один поток, а два, и каждый из них передаёт разные значения прогресса. Теперь немного переделаем код, в событии onCreate формы создадим критическую секцию:

 

var
Form1: TForm1;
CriticalSection: TCriticalSection;

...

procedure TForm1.FormCreate(Sender: TObject);
begin
CriticalSection: =TCriticalSection.Create;
end;

У TCriticalSection есть два нужных нам метода, Enter и Leave, соответственно вход и выход из неё. Поместим наш код в критическую секцию:

procedure TNewThread.Execute;
var
i: integer;
begin
CriticalSection.Enter;
for i: =0 to 100 do
begin
sleep(50);
SendMessage(Form1.Handle, PROGRESS_POS, 0, i);
end;
CriticalSection.Leave;
end;

Попробуйте запустить приложение и нажать несколько раз на кнопку, а потом посчитайте, сколько раз пройдёт прогресс. Понятно, в чем суть? Первый раз, нажимая на кнопку, мы создаём поток, он занимает критическую секцию и начинает работу. Нажимаем второй - создаётся второй поток, но критическая секция занята, и он ждёт, пока её не освободит первый. Третий, четвёртый - все пройдут только по очереди.

Критические секции удобно использовать при обработке одних и тех же данных (списков, массивов) разными потоками. Поняв, как они работают, Вы всегда найдёте им применение.

Пример создания многопоточного приложения в Delphi:

Этот раздел содержит описание шагов, необходимых для создания простого, но показательного примера многопоточного приложения. Мы будем пытаться вычислить число " пи" с максимальной точностью после запятой. Конечно, встроенная в Delphi константа Pi имеет достаточную точность, правильнее сказать — максимальную, допускаемую самым точным 10-байтным форматом для вещественных чисел Extended. Так что превзойти ее нам не удастся. Но этот пример использования потоков может послужить прологом для решения реальных задач.

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

1. В среде Delphi откройте меню File и выберите пункт New Application.

2. Расположите на форме пять меток и один переключатель, как показано на рис. 1. Переименуйте главную форму в fmMain.

3. Откройте меню File и выберите пункт Save Project As. Сохраните модуль как uMain, а проект — как Threads 1.

Рис. 1. Внешний вид формы для приложения Threads'1

4. Откройте меню File и выберите пункт New. Затем дважды щелкните на объекте типа поток (значок Thread Object). Откроется диалоговое окно New Items, показанное на рис. 2.

Рис. 2. Диалоговое окно New Items с выбранным объектом типа " поток"

Рис. 3. Диалоговое окно New Thread Object

5. Когда появится диалоговое окно для именования объекта поток, введите TPiThread и нажмите клавишу Enter (рис. 3). Помимо этого, при желании, вы можете присвоить создаваемому потоку имя, установив флажок Named Thread и задав имя в поле Thread Name. Так как имя потока используется только для удобства обозначения, эту возможность мы использовать не будем.

Delphi создаст новый модуль и поместит в него шаблон для нового потока.

6. Код, вносимый в метод Execute, вычисляет число Pi, используя сходимость бесконечного ряда Лейбница:

Pi = 4 - 4/3 + 4/5 - 4/7 + 4/9 -...

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

Код метода Execute показан ниже:

7. Откройте меню File и выберите пункт Save As. Сохраните модуль с потоком как uPiThread.pas.

8. Отредактируйте главный файл модуля uMain.pas и добавьте модуль uPiThread к списку используемых модулей в секции интерфейса. Он должен выглядеть так:

9. В секции public формы TfmMain добавьте ссылку на создаваемую нить: PiThread: TPiThread;

10. Добавьте в модуль uMain две глобальные переменные

и метод UpdatePi:

Этот метод, если Вы обратили внимание, вызывается из потока посредством процедуры Synchronize. Он отображает текущее значение приближения к числу " пи" и количество итераций.

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

11. Выполните двойной щелчок на свободном месте рабочей области формы, при этом создастся шаблон метода FormCreate. Здесь мы отобразим значение системной константы р±:

12. Выберите на форме переключатель (его название cbcalculate) и назначьте событию Onclick код, создающий и уничтожающий вычислительный поток в зависимости от состояния переключателя:

Таким образом, многопоточное приложение готово к запуску. Если все пройдет нормально, вы увидите картинку, подобную той, которая приведена на рис. 4.

Рис. 4. Выполняющееся приложение Threads1

Вопросы для подготовки к сдаче лабораторной работы:

1. Что такое поток?

2. Какие Вы знаете типы многозадачности в ОС Windows?

3. Что такое процесс?

4. В чем отличие потока от процесса?

5. Для чего необходима процедура Synchronize?

6. Для чего необходимы критические секции?

7. Какие Вы знаете приоритеты потоков?

8. Для чего необходим метод Execute?

9. Как можно определить количество потоков в запущенном процессе?

 

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.