Многопоточные приложения в Delphi
Понятие многопоточности. История возникновения и развития параллельного программирования. Квазимногозадачность на уровне исполняемого процесса. Типы реализации потоков, их взаимодействие и общее ресурсы. Критические секции. Классы и процедуры в Delphi.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 20.09.2013 |
Размер файла | 1,1 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
Размещено на http://www.allbest.ru/
Министерство образования республики Беларусь
Учреждение образования
«Гомельский государственный университет имени Франциска Скорины»
Математический факультет
Кафедра ВМиП
Курсовая работа
Многопоточные приложения в Delphi
Гомель, 2012
Введение
Потоки появились еще в Windows NT, но до определенного времени редко использовались прикладными программистами. В наше время эта тема очень актуальна, когда даже самый захудалый офисный компьютер обладает как минимум двумя процессорными ядрами, не использовать потоки в программах просто неприлично. Например, всё программирование звука написано с использованием потоков, или параллельная проверка орфографии в Microsoft Word.
Целью моей курсовой работы было разработать оконное многопоточное приложение, которое будет выполнять SQL-запросы базы данных, используя несколько потоков, что существенно увеличивает продуктивность программы, что в свою очередь уменьшает время ожидания пользователя.
В первом разделе отчета по моей курсовой работы приведена информация о многопоточности и о типах реализации потоков, во втором разделе была рассмотрена проблема взаимодействия потоков с общими ресурсами, а так же способы решения данных проблем. Классы реализации многопоточности в Delphi, были приведены в третьем пункте, вместе с разработанным мною наследником класса TThread, который является одним из способов реализации потоков в Delphi. В четвертой части представлен интерфейс взаимодействия пользователя с приложением, а так же был приведён пример работы мною разработанного многопоточного приложения.
1. Понятие многопоточности
Параллельное программирование возникло в 1962 г. с изобретением каналов - независимых аппаратных контролеров, позволяющих центральному процессору выполнять новую прикладную программу одновременно с операциями ввода-вывода других (приостановленных) программ. Параллельное программирование (слово параллельное в данном случае обозначает «происходящее одновременно») первоначально было уделом работников операционных систем. В конце 60-х годов были созданы многопроцессорные машины. В результате не только были поставлены новые задачи разработчикам операционных систем, но и появились новые возможности у прикладных программистов.
Всем известно, что Windows система многозадачная. Попросту говоря, это означает, что несколько программ могут работать одновременно под управлением оперативной системы. Все мы открывали диспетчер задач и видели список процессов. Процесс - это экземпляр выполняемого приложения. На самом деле сам по себе он ничего не выполняет, он создаётся при запуске приложения, содержит в себе служебную информацию, через которую система с ним работает, так же ему выделяется необходимая память под код и данные. Для того, чтобы программа заработала, в нём создаётся поток. Любой процесс содержит в себе хотя бы один поток, и именно он отвечает за выполнение кода и получает на это процессорное время. Этим и достигается мнимая параллельность работы программ, или, как её еще называют, псевдопараллельность. Почему мнимая? Да потому, что реально процессор в каждый момент времени может выполнять только один участок кода. Windows раздаёт процессорное время всем потокам в системе по очереди, тем самым создаётся впечатление, что они работают одновременно. Реально работающие параллельно потоки могут быть только на машинах с двумя и более процессорами.
Многопоточность это свойство платформы или приложения (например, операционной системы или виртуальной машины), состоящее в том, что процесс, порождённый в операционной системе, может состоять из нескольких потоков, выполняющихся «параллельно», то есть без предписанного порядка во времени. При выполнении некоторых задач такое разделение может достичь более эффективного использования ресурсов вычислительной машины.
Любая программа содержит хотя бы один поток (главный), в котором она выполняется. Помимо этого, она может порождать любое количество дополнительных потоков, которые будут выполняться в фоновом режиме. У дополнительных потоков приоритет выстраивается такой же, как и у главного потока программы, но программист может увеличить его или уменьшить. Чем выше приоритет потока, тем больше на него отводится процессорного времени.
Сутью многопоточности является квазимногозадачность на уровне одного исполняемого процесса, то есть все потоки выполняются в адресном пространстве процесса. Кроме этого, все потоки процесса имеют не только общее адресное пространство, но и общие дескрипторы файлов.
Время работы процессора разбивается на небольшие интервалы, обычно называемые квантами. Когда квант времени заканчивается, выполнение текущего потока приостанавливается, содержимое регистров процессора сохраняется в специальной области памяти, и он переключается на обработку следующего потока. Когда очередь снова дойдет до этого потока, содержимое регистров будет полностью восстановлено и работа потока продолжится так, как будто она вовсе и не прерывалась. Таким образом, переключение потоков происходит совершенно незаметно для них самих.
К достоинствам многопоточности в программировании можно отнести следующее:
- Упрощение программы в некоторых случаях, за счет использования общего адресного пространства;
- Меньшие относительно процесса временные затраты на создание потока;
- Повышение производительности процесса за счет распараллеливания процессорных вычислений и операций ввода/вывода.
1.1 Типы реализации потоков
Каждый процесс имеет таблицу потоков, аналогичную таблице процессов ядра. Достоинства и недостатки этого типа следующие:
Достоинства:
- возможность реализации на ядре не поддерживающем многопоточность;
- Более быстрое переключение, создание и завершение потоков;
- процесс может иметь собственный алгоритм планирования.
Недостатки:
- Отсутствие прерывания по таймеру внутри одного процесса;
- При использовании блокирующего системного запроса все остальные потоки блокируются;
- Сложность реализации.
Смешанная реализация. Потоки работают в режиме пользователя, но при системных вызовах переключаются в режим ядра. Переключение в режим ядра и обратно является ресурсоемкой операцией и отрицательно сказывается на производительности системы. Поэтому было введено понятие волокна -- облегченного потока, выполняемого исключительно в режиме пользователя.
Создать дополнительный поток в Delphi поможет объект TThread. Ввести объект TThread в программу можно двумя способами:
- с помощью Мастера;
- вручную.
Мастер создания дополнительного потока в Delphi создаёт отдельный модуль, в рамках которого выполняется поток. Выполним:
File -> New -> Other...
В появившейся табличке выбора найдём TThread Object. Появится окошко, в верхнюю строку которого (Class Name) введём имя нашего будущего потока: MyThread. В результате будет создан модуль, содержащий заготовку кода, реализующего дополнительный поток Delphi. Если поток создаётся мастером, т.е. в другом модуле, то не забудьте в основном модуле описать переменную - экземпляр потока. Также, поскольку класс потока описан в другом модуле, имя этого модуля необходимо добавить в секцию uses.
В первом способе класс MyThread был создан мастером в дополнительном модуле. Второй способ состоит в том, что мы сами создаём такой класс в рамках одного из уже существующих модулей программы, например, в модуле Unit1.
2. Взаимодействие протоков и их общее ресурсы
В процессе разработки многопоточного приложения приходится решать две взаимосвязанные проблемы - разграничение доступа к ресурсам и взаимоблокировки. Если несколько потоков обращаются к одному и тому же ресурсу (области памяти, файлу, устройству) при небрежном программировании может возникнуть ситуация, когда сразу несколько потоков попытаются выполнить некие манипуляции с общим ресурсом. При этом нормальная последовательность операций при обращении к ресурсу, скорее всего, будет нарушена. Проблема с разграничением доступа может возникнуть даже при очень простых операциях. Предположим, у нас есть программа, которая создает несколько потоков. Каждый поток выполняет свою задачу, и затем завершается. Мы хотим контролировать количество потоков, активных в данное время, и с этой целью вводим счетчик потоков - глобальную переменную Counter. Процедура потока при этом может выглядеть так:
procedure MyThread.Execute;
begin
Inc(Counter);
...
Dec(Counter);
end;
Одна из проблем, связанных с этим кодом заключается в том, что процедуры Inc и Dec не атомарные (например, процедуре Inc требуется выполнить три инструкции процессора - загрузить значение Counter в регистр процессора, выполнить сам инкремент, затем записать результат из регистра процессора в область памяти Counter). Нетрудно догадаться, что если два потока попытаются выполнить процедуру Inc одновременно, значение Counter может быть увеличено на 1 вместо 2.
В общем случае для решения проблемы разделения доступа используются блокировки - специальные механизмы, которые гарантируют, что в каждый данный момент времени только один поток имеет доступ к некоторому ресурсу. В то время, когда ресурс заблокирован одним потоком, выполнение других потоков, пытающихся получить доступ к ресурсу, приостанавливается. Однако использование блокировок создает другую проблему - взаимоблокировки (deadlocks). Взаимоблокировка наступает тогда, когда потока A блокирует ресурс, необходимый для продолжения работы потока B, а поток B блокирует ресурс, необходимый для продолжения работы потока A. Поскольку ни один поток не может продолжить выполнение, заблокированные ресурсы не могут быть разблокированы, что приводит к повисанию потоков.
2.1 Решение проблем с общими ресурсами
При выполнении нескольких потоков существует вероятность того, что они будут взаимодействовать друг с другом. Для того чтобы синхронизировать свое выполнение и существует несколько методов синхронизации потоков:
- Блоки взаимного исключения (Mutex);
- Переменные состояния;
- Семафоры.
Объекты синхронизации являются переменными в памяти, к которым можно обратиться так же, как к данным. Потоки в различных процессах могут связаться друг с другом через объекты синхронизации, помещенные в разделяемую память потоков, даже в случае, когда потоки в различных процессах вообще невидимы друг для друга.
Объекты синхронизации можно разместить в файлах, где они будут существовать независимо от создавшего их процесса.
Основные ситуации, которые требуют использования синхронизации:
- Если синхронизация - это единственный способ гарантировать последовательность разделяемых данных;
- Если потоки в двух или более процессах могут использовать единственный объект синхронизации совместно. При этом объект синхронизации должен инициализироваться только одним из взаимодействующих процессов, потому что повторная инициализация объекта синхронизации устанавливает его в открытое состояние;
- Если процесс может отобразить файл и существует поток в этом процессе, который получает уникальный доступ к записям. Как только установлена блокировка, любой другой поток в любом процессе, отображающем файл, который пытается установить блокировку, блокируется, пока запись не будет освобождена.
Блоки взаимного исключения (Mutex) -- это объект синхронизации, который устанавливается в особое сигнальное состояние, когда не занят каким-либо потоком. Только один поток владеет этим объектом в любой момент времени, отсюда и название таких объектов (от английского mutually exclusive access -- взаимно исключающий доступ) -- одновременный доступ к общему ресурсу исключается. После всех необходимых действий мьютекс освобождается, предоставляя другим потокам доступ к общему ресурсу. Объект может поддерживать рекурсивный захват второй раз тем же потоком, увеличивая счетчик, не блокируя поток, и требуя потом многократного освобождения.
Семафоры представляют собой доступные ресурсы, которые могут быть приобретены несколькими потоками в одно и то же время, пока пул ресурсов не опустеет. Тогда дополнительные потоки должны ждать, пока требуемое количество ресурсов не будет снова доступно. Семафоры очень эффективны, поскольку они позволяют одновременный доступ к ресурсам. Семафор есть логическое расширение мьютекса -- семафор со счетчиком 1 эквивалентен мьютексу, но счетчик может быть и более 1.
2.2 Критические секции
Наиболее простым в понимании является TCriticalSection или критическая секция. Код, расположенный в критической секции, может выполняться только одним потоком. В принципе код ни как не выделяется, а происходит обращение к коду через критическую секцию. В начале кода находится функция входа в секцию, а по завершению его выход из секции. Если секция занята другим потоком, то потоки ждут, пока критическая секция не освободится.
Рисунок 2.1.2.1 - Схема критической секции
В начале работы критическую секцию необходимо создать:
var
section: TCriticalSection; // глобальная переменная
begin
section.create;
end;
После этого, в необходимых местах кода, нужно установить вход и выход критической секции соответственно, section.enter и section.leave. Критических секций может быть несколько. Поэтому при использовании нескольких функций, в которых могут быть конфликты по данным надо для каждой функции создавать свою критическую секцию. После окончания их использования, когда функции больше не будут вызываться, секции необходимо уничтожить подобным образом section.free.
3. Классы и процедуры реализации многопоточности в Delphi
Среда программирования Delphi предоставляет программисту доступ к возможностям создания многопоточных приложений с помощью специального класса TThread.
С точки зрения операционной системы поток - это ее объект. При создании он получает дескриптор и отслеживается ОС. Объект класса TThread - это конструкция Delphi, соответствующая потоку. Этот объект создается до реального возникновения потока в системе и уничтожается после его исчезновения. Другая отличительная черта класса TThread - это совместимость с библиотекой визуальных компонентов VCL.
Класс TThread включает в себя следующие элементы:
1. Constructor Create (Create Suspended: Boolean). В качестве аргумента он получает параметр CreateSuspended. Если его значение равно True, вновь созданный поток не начинает выполняться до тех пор, пока не будет сделан вызов метода Resume. В случае, если CreateSuspended имеет значение False, поток начинает исполнение и конструктор завершается;
2. Destructor Destroy; override. Деструктор Destroy вызывается, когда необходимость в созданном потоке отпадает. Деструктор завершает его и высвобождает все ресурсы, связанные с объектом TThread;
3. Procedure Resume. Метод Resume класса TThread вызывается, когда поток возобновляется после остановки, или если он был создан с параметром create Suspended, равным True;
4. Procedure Suspend. Вызов метода Suspend приостанавливает поток с возможностью повторного запуска впоследствии. Метод Suspend приостанавливает поток вне зависимости от кода, исполняемого потоком в данный момент; выполнение продолжается с точки останова;
5. Property Suspended: Boolean. Свойство Suspended позволяет программисту определить, не приостановлен ли поток. С помощью этого свойства можно также запускать и останавливать поток. Установив suspended в True, будет получен тот же результат, что и при вызове метода Suspend -- приостановку. Наоборот, установка Suspended в False возобновляет выполнение потока, как и вызов метода Resume;
6. Function WaitFor: Integer. Метод WaitFor предназначен для синхронизации потоков и позволяет одному потоку дождаться момента, когда завершится другой поток. Если внутри потока FirstThread имеется код:
Code := SecondThread.WaitFor;
то это означает, что поток FirstThread останавливается до момента завершения потока SecondThread. Метод WaitFor возвращает код завершения ожидаемого потока;
7. Property Priority: TThreadPriority. Свойство Priority позволяет запросить и установить приоритет потоков. Приоритет определяет, насколько часто поток получает время процессора. Допустимыми значениями приоритета являются tpIdie, tpLowest, tpLower, tpNormal, tpHigher, tpHighest и tpTimeCritical; delphi многопоточность программирование класс
8. Procedure Synchronize (Method: TThreadMethod). Этот метод относится к секции protected, то есть может быть вызван только из потомков TThread. Delphi предоставляет программисту метод synchronize для безопасного вызова методов VCL внутри потоков. Метод synchronize дает гарантию, что к каждому объекту VCL одновременно имеет доступ только один поток. Аргумент, передаваемый в метод synchronize, -- это имя метода, который производит обращение к VCL;
9. Procedure Execute; virtual; abstract. Эта процедура является главным методом объекта TThread. В теле метода должен содержаться код, который представляет собой программу потока. Метод Execute класса TThread объявлен как абстрактный;
10. Property ReturnValue: Integer. Свойство ReturnValue позволяет узнать и установить значение, возвращаемое потоком по его завершении. Эта величина полностью определяется пользователем. По умолчанию поток возвращает ноль, но если программист захочет вернуть другую величину, то простое изменение свойства ReturnValue внутри потока позволит получить эту информацию другим потокам. Это, например, может пригодиться, если внутри потока в ходе его выполнения возникла какая-либо сложная ситуация.
3.1 Разработанный наследник класса TThread
Был разработан наследник стандартного класса TThread под названием TMyThread:
type
TMyThread = class(TThread)
constructor Create;
private
procedure WorkSQL(str: string; Query: TADOQuery);
protected
procedure Execute(); override;
public
end;
В нем была добавлена новая процедура WorkSQL (str: string; Query: TADOQuery), в которую передается строковый параметр str, отвечающий за искомое наименование товара в базе данных, а так же параметр Query типа TADOQuery, который собственно и будет выполнять запрос в бузу данных.
Так же был перегружена процедура Execute родительского класса:
procedure TMyThread.Execute;
var
Query:TADOQuery;
j: integer;
begin
with ListString do
begin
Query:=DM2.CreateSQL;
while not full do
begin
CS.Enter;
j:=GetIndex;
CS.Leave;
if j<>-1 then
begin
WorkSQL(names[j],Query);
if Query.FieldByName('name').AsString<>'' then
good.Add(names[j])
else
bad.Add(names[j]);
Form1.sGauge1.Progress:=Form1.sGauge1.Progress+1;
end;
end;
Query.Free;
end;
end;
В процедуре создаётся объект класс TADOQuery с помощью функции CreateSQL принадлежащая написанному мною объекту класса TDataModule, которая возвращает указатель на созданный внутри этой функции объект класса TADOQuery.
function TDM2.CreateSQL():TADOQuery;
var
Query:TADOQuery;
begin
Query:=TADOQuery.Create(DM2);
Query.Connection:= ADOConnection1;
Result:=Query;
end;
Данная функция создает объект класса TADOQuery и с помощью ранее настроенного компонента TADOConnection устанавливает связь только что созданного объект класса TADOQuery с базой данных.
Процедура Execute проверяет, есть ли ещё непроверенные записи в списке объекта класса TListString.
type
TListString = class
names: array of string;
good: TListString;
bad: TListString;
count: integer;
index: integer;
full: boolean;
procedure Add(name: string);
constructor Create(fileName: string);
constructor Create1;
destructor Destroy;
function GetIndex():integer;
end;
Список записей объекта класса TListString формируется при создании объекта данного класса с помощью конструктора Create, в который передаётся файл, который был выбран пользователь при помощи диалогового окна. Так же в данном конструкторе вызывается конструктор Create1, для создания двух объектов этого же класса TListString, в которых будут создаваться списки с имеющимися и отсутствующими в базе данных записями.
В случае, если в списке записей имеются те, которые ещё не были проверены, то поток берёт следующую запись из списка записей с помощью функции GetIndex объекта класса TListString и проверяет на наличие наименования данного товара в базе данных, вызывая процедуру WorkSQL. В зависимости от результата запроса проверяемое значение заносится либо в список с имеющимися либо в список с отсутствующими наименованиями товара. Так же после проверки очередного значения из списка поток увеличивает полосу прогресса. После того как все записи из списка значений будут проверены, поток очистит используемый внутри данного класса объект класса TADOQuery.
function TListString.GetIndex():integer;
begin
if index<count then
begin
Result:=index;
inc(index);
end else
begin
Result:=-1;
full:=true;
end;
end;
Функция GetIndex в зависимости от того, существует ли ещё непроверенные записи, возвращает номер следующей свободной записи и помечает его как уже проверенный, тем самым гарантирует уникальность возвращаемого номера, то есть обеспечивает, что каждый номер из списка будет возвращён только единожды.
4. Созданное приложение
4.1 Интерфейс взаимодействия программы с пользователем
Для того чтобы немного разнообразить интерфейс взаимодействия программы с пользователем мною была использована посторонняя библиотека компонентов AlphaSkin, которая позволяет изменять внешний вид стандартных компонентов, делая их более красочными. При запуске приложения перед пользователем открывается главное окно (рисунок 4.1.1).
Рисунок 4.1.1 - Главное окно приложения
Пользователю предоставлена возможность выбора желаемого количества потоков при помощи объекта класса TSpinEdit (рисунок 4.1.2).
Рисунок 4.1.2 - Выбор количества потоков
Так же пользователю предоставлена возможность выбора внешнего вида, в частности главного окна, приложения на свой вкус. Для этой цели был использован компонента, объекта класса TComboBox, в выпадающем списке которого находится перечень доступных стилей внешнего оформления приложения (рисунок 4.1.3).
Рисунок 4.1.3 - Выбор внешнего вида приложения
Для того чтобы пользователь мог указать исходный файл с наименованиями товаров, которые нужно проверить на наличие в базе данных, пользователю необходимо нажать на кнопку «Указать источник данных», после чего откроется диалоговое окно объекта класса TOpenDialog, где пользователь может выбрать искомый файл (рисунок 4.1.4).
Рисунок 4.1.4 - Диалоговое окно для выбора файла
После чего пользователь должен нажать на кнопку «Запустить», для того чтобы программа начала проверку выбранного пользователем файла. После окончания проверки программа выдаст сообщение о том, что проверка успешна завершена, что свидетельствует о том, что были созданы два файла «good» и «bad» (рисунок 4.1.5).
Рисунок 4.1.5 - Сообщение об окончании работы программы
В случае когда пользователь попытается завершить работу приложения, в то время когда программа ещё будет выполнять проверку, пользователь уведет соответствующие сообщения, в котором будет предоставлен выбор отменить закрытие приложения либо закрыть его принудительно не дожидаясь окончания проверки (рисунок 4.1.6).
Рисунок 4.1.6 - Предупреждение о несвоевременном закрытии
4.2 Исходный код приложения
За время выполнения курсовой работы был разработан следующий код программы:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtCtrls, sPanel, sDialogs, sSkinManager,
sComboBoxes, sButton, sGauge, sLabel, sEdit, sSpinEdit, sGroupBox, acMagn,
acPathDialog, Mask, sMaskEdit, sCustomComboEdit, sTooledit, Buttons,
sSpeedButton, sColorSelect, sComboBox, sFontCtrls, sBitBtn, ToolWin,
acCoolBar, SyncObjs, DM, ADODB;
type
TListString = class
names: array of string;
good: TListString;
bad: TListString;
count: integer;
index: integer;
full: boolean;
procedure Add(name: string);
constructor Create(fileName: string);
constructor Create1;
destructor Destroy;
function GetIndex():integer;
end;
type
TMyThread = class(TThread)
constructor Create;
private
procedure WorkSQL(str: string; Query: TADOQuery);
protected
procedure Execute(); override;
public
end;
type
TForm1 = class(TForm)
SM1: TsSkinManager;
thCount: TsSpinEdit;
P1: TsPanel;
sGauge1: TsGauge;
bOpen: TsButton;
bStart: TsButton;
sLabelFX1: TsLabelFX;
Style: TsComboBox;
sLabel1: TsLabel;
sBitBtn1: TsBitBtn;
OpenDialog1: TsOpenDialog;
procedure bOpenClick(Sender: TObject);
procedure bStartClick(Sender: TObject);
procedure sBitBtn1Click(Sender: TObject);
procedure StyleChange(Sender: TObject);
procedure sGauge1Change(Sender: TObject);
procedure WriteFile;
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
Public
procedure Progres;
end;
var
Form1: TForm1;
CS: TCriticalSection;
ListString: TListString;
implementation
{$R *.dfm}
procedure TForm1.bOpenClick(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
ListString:=TListString.Create(OpenDialog1.FileName);
sGauge1.MaxValue:=ListString.count;
bStart.SetFocus;
end;
end;
procedure TForm1.bStartClick(Sender: TObject);
var
i: integer;
begin
bStart.Enabled:=false;
CS:=TCriticalSection.Create;
ListString.full:=false;
for i:=1 to StrToInt(thCount.Text) do
TMyThread.Create;
end;
procedure TForm1.sBitBtn1Click(Sender: TObject);
begin
if (bStart.Enabled=false) and (sGauge1.Progress<>sGauge1.MaxValue) then
begin
if Messagebox(Form1.Handle, 'Процесс будет остановлен, хотите продолжить','Предупреждение',36)=6 then
close
else
exit;
end else
Close;
end;
procedure TForm1.StyleChange(Sender: TObject);
begin
SM1.SkinName:=Style.Text;
// Afterburner, BlueIce, Deep, KaraKum, TheFrog, UnderWater, Wood, WOT.
end;
procedure TForm1.WriteFile;
var
i: integer;
f: TextFile;
begin
AssignFile(f,'good.txt');
rewrite(f);
for i:=0 to ListString.good.count-1 do
writeln(f,ListString.good.names[i]);
CloseFile(f);
AssignFile(f,'bad.txt');
rewrite(f);
for i:=0 to ListString.bad.count-1 do
writeln(f,ListString.bad.names[i]);
CloseFile(f);
end;
procedure TForm1.sGauge1Change(Sender: TObject);
begin
if sGauge1.Progress=sGauge1.MaxValue then
begin
WriteFile;
MessageDlg('Программа успешно завершена',mtInformation,[mbOK],0);
end;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
bOpen.SetFocus;
end;
function TListString.GetIndex():integer;
begin
if index<count then
begin
Result:=index;
inc(index);
end else
begin
Result:=-1;
full:=true;
end;
end;
procedure TListString.Add(name: string);
begin
inc(count);
SetLength(names,count);
names[count-1]:=name;
end;
constructor TListString.Create1;
begin
count:=0;
index:=0;
end;
constructor TListString.Create(fileName: string);
var
f: TextFile;
a: string;
begin
good:= TListString.Create1;
bad:= TListString.Create1;
count:=0;
index:=0;
AssignFile(f,fileName);
Reset(f);
readln(f,a);
while(a<>'') do
begin
Add(a);
Readln(f,a);
end;
CloseFile(f);
end;
destructor TListString.Destroy;
begin
names:=nil;
good.Free;
bad.Free;
end;
constructor TMyThread.Create;
begin
inherited Create(false);
end;
procedure TMyThread.WorkSQL(str: string; Query: TADOQuery);
begin
Query.SQL.Text:='SELECT name FROM list WHERE name='''+str+'''';
Query.Active:=true;
Query.ExecSQL;
end;
procedure TForm1.Progres;
begin
sGauge1.Progress:=sGauge1.Progress+1;
end;
procedure TMyThread.Execute;
var
Query:TADOQuery;
j: integer;
begin
with ListString do
begin
Query:=DM2.CreateSQL;
while not full do
begin
CS.Enter;
j:=GetIndex;
CS.Leave;
if j<>-1 then
begin
WorkSQL(names[j],Query);
if Query.FieldByName('name').AsString<>'' then
good.Add(names[j])
else
bad.Add(names[j]);
Synchronize(Form1.Progres);
end;
end;
Query.Free;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ListString.Free;
CS.Free;
end;
end.
unit DM;
interface
uses
SysUtils, Classes, DB, DBTables, ADODB, Dialogs;
type
TDM2 = class(TDataModule)
ADOConnection1: TADOConnection;
SQL123: TADOQuery;
DataSource1: TDataSource;
private
{ Private declarations }
public
function CreateSQL():TADOQuery;
end;
var
DM2: TDM2;
implementation
{$R *.dfm}
function TDM2.CreateSQL():TADOQuery;
var
Query:TADOQuery;
begin
Query:=TADOQuery.Create(DM2);
Query.Connection:= ADOConnection1;
Result:=Query;
end;
end.
4.3 Пример использования программы
В базе данных имеется набор наименований мобильных устройств сотовой связи (рисунок 4.2.1).
Рисунок 4.2.1 - Список наименования товаров
К примеру, нам нужно проверить некоторые наименования товаров на наличие их в азе данных, список которых находится в файле Audit.txt (рисунок 4.2.2).
Рисунок 4.2.2 - Содержимое файла Audit.txt
В первом случае мы выполним проверку используя один поток, во втором случае мы изменим значение количество потоков на большее чем в первом случае, к примеру, будем использовать три потока. В итоге во втором случае программа предъявила нам результаты (рисунки 4.2.3 - 4.2.4) намного раньше, чем в первом случае, тем самым значительно уменьшив ожидание пользователя.
Рисунок 4.2.3 - Содержимое файла с не имеющимися значениями
Рисунок 4.2.4 - Содержимое файла с имеющимися значениями
Заключение
За время выполнения курсовой работы были выполнены все поставленные задачи, то есть было спроектировано и разработано оконное многопоточное приложение с использованием SQL запросов для проверки текстового файла на имеющийся либо отсутствующий товар в базе данных. Так же были изучены методы создания и синхронизации потоков для того, чтобы уменьшить время ожидания пользователя и разрешить проблемы с взаимодействием потоков и их доступом к общим ресурсам, для правильной работы приложения.
В результате проделанной работы была создана программа, которая при помощи нескольких потоков обрабатывает заданную информацию и формирует два текстовых файла, в которых хранятся списки с имеющимися и отсутствующими наименованиями товара в базе данных.
Список использованных источников
1. Эндрюс Р. Основы многопоточного, параллельного и распределённого программирования / Р. Эндрюс. - М.: Вильмс. - 512с.: ил.
2. Тейксейра, С. Delphi 5. Руководство разработчика: учеб. пособие в 2 т. / С. Тейксейра, К. Пачеко - М.: Издательский дом «Вильямс», 2000. - Том 2. Разработка компонентов и программирование баз данных. - 992 с.
3. Шкрыль, А. Разработка клиент-серверных приложений в Delphi. - СПб: БХВ-Петербург, 2006 - 480 с.
4. Ревнч Ю. В. Нестандартные приёмы программирования на Delphi. - СПб.: БХВ-Петербург, 2005. - 560 с: ил.
Размещено на Allbest.ru
Подобные документы
Предмет объектно-ориентированного программирования и особенности его применения в средах Паскаль, Ада, С++ и Delphi. Интегрированная среда разработки Delphi: общее описание и назначение основных команд меню. Процедуры и функции программы Delphi.
курсовая работа [40,8 K], добавлен 15.07.2009Общая характеристика системы программирования Delphi, а также принципы создания ее компонентов. Описание значений файлов приложения, созданного с помощью Delphi. Структура и свойства библиотеки визуальных компонентов (Visual Component Library или VCL).
отчет по практике [1,1 M], добавлен 07.12.2010Общая характеристика интерфейса языка программирования Delphi. Рассмотрение окна редактора кода, конструктора формы, инспектора объектов и расширения файлов. Ознакомление с основными этапами создания и сохранения простого приложения; проверка его работы.
презентация [184,3 K], добавлен 18.03.2014Характеристика системы программирования. Главные составные части Delphi. Интерфейс программного приложения. Результаты работы программы. Руководство системного программиста и оператора. Язык программирования Delphi, среда компилятора Borland 7.0.
курсовая работа [1,6 M], добавлен 29.05.2013Эффективные средства разработки программного обеспечения. Технология визуального проектирования и событийного программирования. Конструирование диалоговых окон и функций обработки событий. Словесный алгоритм и процедуры программы Borland Delphi 7 Studio.
дипломная работа [660,2 K], добавлен 21.05.2012Delphi как строго типизированный объектно-ориентированный язык. Общее понятие о приложении "DreamBook", его главные задачи. Модель бизнес процесса. Диаграмма прецедентов: спецификация, ограничения и отношения. Модель анализа, общий алгоритм метода.
контрольная работа [190,4 K], добавлен 22.11.2013Требования по разработке программы часов, особенности и преимущества языка Delphi 7. Разработка блок-схем алгоритмов и описание процесса программирования. Основные процедуры для реализации, назначение, функционирование и условие работы с программой.
курсовая работа [1,2 M], добавлен 14.07.2012Средства языка программирования Delphi. Структурные типы данных. Строковые переменные, массивы, множества, файлы. Механизм классов в C++. Интерфейсный и описательный обзоры классов в Delphi. Работа с текстовыми и бинарными файлами прямого доступа.
курсовая работа [990,4 K], добавлен 07.08.2012История интегрированной среды разработки, версии Delphi. Организация библиотеки компонентов. Страница Additional, ряд часто используемых компонентов общего назначения. Исполняемый файл программы "Архиватор текстовых файлов", интерфейс приложения.
курсовая работа [1019,0 K], добавлен 16.05.2017Borland Delphi 7 как универсальный инструмент разработки, применяемый во многих областях программирования, функции: добавление информации об абитуриентах в базу данных, формирование отчетов. Рассмотрение и характеристика основных компонентов Delphi.
контрольная работа [3,6 M], добавлен 18.10.2012