![](/user_photo/2706_HbeT2.jpg)
- •Содержание
- •Рекомендации к проведению лабораторных работ
- •Комментарии в тексте программы
- •Компиляция и запуск программы на выполнение
- •Переменные и константы
- •Операторы и выражения
- •Оператор присваивания
- •Арифметические операции
- •Логические операции
- •Составной оператор begin..end
- •Условный оператор if..then
- •Оператор-селектор case..of
- •Операторы обработки циклов
- •Цикл с параметром for .. do
- •Цикл с предусловием while..do
- •Цикл с постусловием repeat..until
- •Процедуры break и continue
- •Оператор with..do
- •Процедуры и функции
- •Процедуры
- •Функции
- •1. Фундаментальные структуры данных
- •Общее понятие типа данных
- •Простой тип
- •Перечислимые типы данных
- •Поддиапазонны
- •Строковый тип
- •Структурные типы
- •Массивы
- •Записи
- •Множества
- •Представление структур в памяти
- •Задание
- •2. Работа с последовательностями, файлы
- •Доступ к файлу
- •Операции над файлами
- •Окончание файла
- •Пример работы с файлом
- •Задание
- •3. Анализ алгоритмов
- •Рост функций
- •Задание
- •4. Простейшие методы сортировки массивов
- •Оценка алгоритмов сортировки
- •Шейкер-сортировка
- •Сортировка простыми вставками
- •Сортировка бинарными вставками
- •Задание
- •5. Улучшенные методы сортировки массивов
- •Сортировка с помощью включений с уменьшающимися расстояниями (сортировка Шелла)
- •Пирамидальная сортировка
- •Сортировка с разделением (быстрая сортировка)
- •Задание
- •6. Сортировка последовательных файлов
- •Сортировка простым слиянием
- •Естественное слияние
- •Задание
- •7. Рекурсивные алгоритмы
- •Сравнение рекурсии и итерации
- •Задание
- •8. Динамические структуры данных, связные списки
- •Списки
- •Пример создания и заполнения списка
- •Задание
- •9. Нелинейные структуры данных
- •Граф
- •Бинарное дерево
- •Задание
- •10. Алгоритмы на графах
- •Алгоритмы обхода в глубину и по уровням
- •Построение минимального остовного дерева
- •Поиск кратчайшего пути
- •Задание
- •11. Поиск данных
- •Двоичный (бинарный) поиск элемента в массиве
- •Интерполяционный поиск элемента в массиве
- •Алгоритм Бойера-Мура
- •Задание
- •12. Хеширование
- •Отечественный стандарт хеширования
- •Создание хеш-функции
- •Хеш-функции для строковых значений, алгоритм Гонера
- •Задание
- •13. Методы сжатия текстовых данных
- •Метод “Running”
- •Словарные методы сжатия
- •Алгоритм Хаффмана
- •Задание
- •14. Алгоритмы вывода графических примитивов
- •Рисование отрезка
- •Прямое вычисление координат
- •Инкрементный алгоритм Брезенхэма
- •Простейший алгоритм закрашивания замкнутой области
- •Задание
- •15. Псевдослучайные последовательности
- •Метод середин квадратов
- •Линейный конгруэнтный метод
- •Генератор псевдослучайных чисел, поставляемый с системой
- •Оценка качества генератора ПСП
- •Задание
- •16. Параллельные алгоритмы
- •Пример многопоточного приложения
- •Задание
- •Задание на СКР
- •Вариант 1. Клеточные автоматы
- •Вариант 2. Раскрашивание карты
- •Вариант 3. Крисс-кросс
- •Вариант 4. Лабиринт
- •Список использованной литературы
- •Приложение A. Справочник по функциям Delphi
- •Операции с порядковыми типами
- •Математические функции и процедуры
- •Генерация псевдослучайного числа
- •Преобразование типов данных
- •Работа с памятью
- •Приложение Б. Компонент-сетка TStringGrid
- •Приложение В. Компонент-диаграмма TChart
- •Приложение Д. Элементарный поток – класс TThread
![](/html/2706/363/html_6nPrlBqXsZ.l5CD/htmlconvd-KP4AzT91x1.jpg)
91
Приложение Д. Элементарный поток – класс TThread
Для программной реализации потока в Delphi описан специальный класс TThread. Так как класс абстрактен, то в первозданном виде он нам никогда не понадобиться. Но созданные на его основе объекты превосходно инкапсулируют полнофункциональные потоки.
На палитре компонентов Delphi элемент управления TThread вы не найдёте. Для того, чтобы самое обычное приложение сделать многопоточным требуется к уже существующему приложению добавить специальный программный модуль. Для этого, после создания нового приложения выберите пункт меню File – New – Other. И на вкладке “New” диалогового окна “New Items" найдите пиктограмму ThreadObject. После нажатия кнопки OK в новом диалоговом окне требуется ввести имя нового класса – потока. Например: TMyThread. В результате выполненных действий Delphi создаёт представленный ниже шаблон, предназначенный для описания потока. Обратите внимание, что в секции Protected среда Delphi уже подготовила перекрытую процедуру Execute(). Именно в теле этой процедуры программист располагает программный код, который станет исполняться в отдельном потоке. Если подзадача вызывается многократно, то строки кода помещаются внутрь тела цикла, выход из которого завершает работу потока.
Рисунок – Создание многопоточной программы
unit Unit2;
interface
uses Classes; type
TMyThread = class(TThread) //класс TMyThread создаётся на базе абстрактного TThread private
{ Private declarations } protected
procedure Execute; override; end;
implementation
procedure TMyThread.Execute; begin
{место для исходного кода обслуживающего поток} end;
end.
![](/html/2706/363/html_6nPrlBqXsZ.l5CD/htmlconvd-KP4AzT92x1.jpg)
92
Для запуска потока вызывайте метод:
procedure Execute;
Говоря образно, эта процедура заставит биться сердце потока.
При старте приложения автоматического создания экземпляра класса TMyThread не произойдёт. Для рождения нового потока Delphi потребует явного обращения к его конструктору:
constructor Create(CreateSuspended : Boolean);
Единственный параметр конструктора определяет, каким образом производится запуск потока. Если параметр CreateSuspended установлен в False, то поток стартует немедленно сразу после создания экземпляра класса. Если же передаётся значение true, то запуск потока откладывается до его явного вызова из какой-нибудь части кода программы.
var Thread: TMyThread;
…
procedure TfrmMain.FormCreate(Sender: TObject); begin
MyThread:=TMyThread.Create(true); end;
Для временной приостановки выполнения потока используйте процедуру:
procedure Suspend;
Для возобновления работы приостановленного потока:
procedure Resume;
Причём возобновление выполнения потока произойдёт именно с того места (с той строки кода), где он был приостановлен. Два названных метода дублируются свойством:
property Suspended : Boolean;
Если Вы установите свойство в true, то поток приостановится, false – вновь активизируется.
Для временной приостановки потока программисты Delphi часто пользуются процедурой Win32 API Sleep(). В качестве параметра передаётся число миллисекунд, на которые необходимо заморозить подзадачу.
procedure Sleep(milliseconds: Cardinal);
Поток, переведённый в состояние сна с помощью этого метода, не снижает производительность системы, так как не требует выделения ему квантов времени.
Для полной остановки потока вызывайте метод:
procedure Terminate;
Это способ остановки называется мягким. Процедура просто-напросто присваивает значение true свойству:
property Terminated: Boolean;
В этом случае Delphi не настаивает, на немедленном прекращении работы потока и разрешает ему достичь логического конца. Поясняю это утверждение на примере. Обычно исполняемый потоком код заключается в рамки цикла while..do или repeat..until, условием выхода из которого будет переход свойства Terminated в состояние true.
Procedure TMyThread.Execute;
Begin
While Terminated=false do //условие продолжения цикла
Begin
{исполняемый код}
End; end;
![](/html/2706/363/html_6nPrlBqXsZ.l5CD/htmlconvd-KP4AzT93x1.jpg)
93
Как видите, если в момент вызова метода Terminated() выполнялся код расположенный внутри конструкции begin..end, то он не будет немедленно прерван. Останов произойдёт только при проверке условия цикла. Если есть мягкий способ остановки потока, то где-то в недрах Windows можно обнаружить и “жёсткий”. Если вы сторонник радикальных решений и категорически настаиваете на том, чтобы поток завершился немедленно, то пригодится функция из арсенала Windows API.
Function TerminateThread(hThread : THandle; ExitCode : Cardinal): boolean;
Здесь hThread – дескриптор потока, ExitCode – программный код выхода из потока, в простейшем случае передавайте значение 0. Если функция завершается успешно, то она вернёт не нулевое значение. Дескриптор потока вы найдёте в свойстве:
property Handle: THandle;
TerminateThread(Thread1.Handle, 0);
Останов потока сопровождается вызовом обработчика события:
property OnTerminate: TNotifyEvent;
Если установить в true свойство:
property FreeOnTerminate: Boolean;
то сразу после останова поток уничтожится. Иначе за вызов деструктора потока отвечаете Вы. Если выполнение метода Execute() прервалось в результате ошибки, и ошибка не была обработана в рамках этого метода, то в свойство только для чтения:
property FatalException: TObject; //только для чтения
будет записан объект ошибки. Это свойство, по крайней мере, можно применять для проверки корректности завершения метода Execute().
Ещё одним способом, косвенно проверяющим корректность завершения работы потока, является использование свойства:
property ReturnValue: Integer;
Это служебная переменная, в которую можно записывать данные, например о количестве запусков потока. Свойство ReturnValue часто применяется совместно с методом:
function WaitFor: LongWord;
Функция предназначена для организации ожидания, пока какой-нибудь другой поток не выполнит поставленную перед ним задачу. Функция возвращает значение, содержащееся в свойстве ReturnValue ожидаемого потока.
Приоритет потока
Приоритет потока формируется двумя составляющими: приоритетом процесса, которому принадлежит поток, и непосредственно приоритетом этого потока. Приоритет потока определяется свойством:
property Priority: TThreadPriority;
Возможные значения, которые может принимать приоритет, приведены в таблице 21.2.
Таблица. Описание приоритета потока, класс TThreadPriority
Значение |
Описание |
tpIdle |
Фоновый приоритет. Поток с таким приоритетом выполняется только при отсутствии хоть ка- |
tpLowest |
кой либо загрузки процессора. |
Низкий приоритет. |
|
tpLower |
Пониженный приоритет. |
tpNormal |
Нормальный приоритет, соответствующий поведению обычной программы. |
tpHigher |
Повышенный приоритет. Использование потоков с таким или более высоким приоритетом |
|
весьма критично скажется на производительности остальных потоков. |
|
|
![](/html/2706/363/html_6nPrlBqXsZ.l5CD/htmlconvd-KP4AzT94x1.jpg)
|
94 |
tpHighest |
Высочайший приоритет. Применяется только для потоков, которые выполняются в кратчайшие |
tpTimeCritical |
промежутки времени. |
Приоритет реального времени, будет обладать приоритетом большим, чем у многих процессов |
|
|
операционной системы. |
procedure TfrmMain.FormCreate(Sender: TObject); begin
Thread1:=TMyThread.Create(TRUE);
Thread1.Priority:=tpIdle;
Thread1.Resume; end;
Без особой на то необходимости старайтесь не создавать потоков, с приоритетом выше нормального. Такой поступок может привести к тому, что системные ресурсы будут перенацелены на обслуживание этой задачи, а это в свою очередь снизит общую производительность системы.
Время выполнения потока
Операционная система позволяет оценить время процессора затраченное на любой из потоков процесса. Для этого предназначен метод:
Function GetThreadTimes(hThread : THandle; var CreationTime, ExitTime, KernelTime, UserTime : TFileTime) : boolean;
Параметры и порядок применения метода аналогичен изученной в начале главы функции GetProcessTimes() за исключением того, что здесь первый параметр – дескриптор интересующего нас потока, а не процесса.
Синхронизация потока с методами VCL
Если из тела процедуры Execute() Вам необходимо осуществить вызов любого метода или обратиться к свойству компонента библиотеки VCL, то обязательно используйте синхронизирующий метод:
procedure Synchronize(Method: TThreadMethod);
Задача метода – защита от гонок потоков, он гарантирует, что к каждому объекту VCL одновременно получит доступ только один поток.