- •Министерство образования и науки российской федерации федеральное агентство по образованию
- •Кафедра систем автоматизированного проектирования
- •Введение
- •1.2.2. Пользовательский интерфейс
- •1.2.3. Файловые системы
- •1.3. Порядок выполнения работы
- •1.4. Содержание отчета
- •Цель работы.
- •1.5. Контрольные вопросы и задания
- •2. Лабораторная работа № 2 «Утилиты ос Windows xp»
- •2.1. Цель работы:
- •2.2. Теоретическая часть
- •2.2.1. Программа получения сведений о системе
- •2.2.2. Программа архивации данных
- •2.2.3. Программа проверки диска
- •2.2.4. Программа дефрагментации дисков
- •2.2.5. Программа очистки жесткого диска
- •2.2.6. Программа «Восстановление системы»
- •2.3. Порядок выполнения работы
- •2.4. Содержание отчета
- •2.5. Контрольные вопросы и задания
- •3.2.2. Команды для работы с файлами и папками
- •3.2.3. Внутренние команды
- •3.2.4. Команды (поддержки) пакетных файлов
- •If exist *.Rpt echo Отчет получен.
- •3.3. Порядок выполнения работы
- •3.4. Содержание отчета
- •Цель работы.
- •3.5. Контрольные вопросы и задания
- •4. Лабораторная работа № 4 «Настройка и оптимизация среды Windows xp»
- •4.1. Цель работы:
- •4.2. Теоретическая часть
- •4.2.1. Индивидуальная настройка рабочего стола
- •4.2.2. Диспетчер задач (Task Manager)
- •4.2.3. Планировщик заданий (Task Scheduler)
- •4.2.4. Средства поддержки виртуальной памяти
- •4.2.5. Другие средства оптимизации
- •4.3. Порядок выполнения работы
- •4.4. Содержание отчета
- •Цель работы.
- •4.5. Контрольные вопросы и задания
- •5.2.2. Синхронизация потоков
- •5.2.3. Создание многопоточных приложений
- •5.2.4. Синхронизация порожденного потока с родительским
- •5.2.5. Управление приоритетом обслуживания потока
- •5.2.6. Приостановка и продолжение работы потока
- •5.3. Порядок выполнения работы
- •5.4. Содержание отчета
- •Цель работы.
- •5.5. Контрольные вопросы и задания
- •Приложение 1. Оформление отчета по лабораторной работе
- •1. Цель работы.
- •Приложение 2. Оформление реферата по выбранной теме
- •Приложение 3. Фрагменты текста программы
- •Void __fastcall Synhr1();// вызывается
- •Void __fastcall Synhr2();// вызывается
- •Int X,y; // Хранит координаты шарика
- •Библиографический список (Учебники и учебные пособия)
- •(Общие вопросы)
- •(Графический интерфейс пользователя)
- •(Семейство Windows)
5.2.4. Синхронизация порожденного потока с родительским
При программировании метода Execute невозможно просто обратиться к свойствам и методам форм, а также их компонентов, поскольку эти действия приводят к конфликту между потоками. Например, нельзя изменить свойство Caption формы, потому что в этот момент главная программа может его читать. Проблема состоит в том, что, разделяя время работы процессора, ОС может в любой момент прервать поток и передать управление другому потоку. Если поток не успеет скопировать все символы в свойство Caption за отведенный ему квант времени и будет прерван, то главный поток программы прочтет из этого свойства некорректное значение. Описанная ситуация относится к числу самых безболезненных, на самом деле последствия одновременного доступа к общим объектам оказываются непредсказуемыми и могут привести даже к аварийному завершению работы приложения.
Чтобы в потоках работать с формами и компонентами, нужно синхронизировать работу потока с главной программой. В классе потока необходимо объявить метод, который выполняет установку свойства Caption формы:
void __fastcall TMyThread::SetFormCaption()
{
Form1->Caption = "Searching..." ;
}
Чтобы объект Form1 был видим из модуля MyThrd, необходимо подключить в модуль MyThrd заголовочный файл Main.h (используя директиву # include).
В программном коде потока (в методе Execute) следует вызвать специальный метод Synchronize и передать ему ссылку на свой метод:
void __fastcall TMyThread::Execute()
{
…
Synchronize(SetFormCaption) ;
…
}
Метод Synchronize дождется подходящего момента времени и выполнит указанный вами метод атомарно по отношению к главному потоку приложения. Такое решение исключает все возможные конфликты.
5.2.5. Управление приоритетом обслуживания потока
По истечении каждого кванта ОС выполняет планирование потоков, принимая решение о том, какому из них передать управление. Планирование потоков выполняется в соответствии со шкалой приоритетов. Очередной квант времени процессора отдается потоку с наивысшим приоритетом. Если несколько потоков имеют одинаковый приоритет, то управление передается тому, который ожидает своей очереди дольше всех.
Приоритет потока представлен в классе TThread свойством Priority. Приоритет потока можно повышать и понижать по мере необходимости. Возможные значения свойства перечислены в таблице 9.
Таблица 9
Значение |
Описание |
tpIdle tpLowest tpLower tpNormal tpHigher tpHighest tpTimeCritical |
Поток выполняется, только если система находится в режиме ожидания Приоритет потока на два пункта ниже обычного Приоритет потока на один пункт ниже обычного Поток имеет обычный приоритет Приоритет потока на один пункт выше обычного Приоритет потока на два пункта выше обычного Поток имеет наивысший приоритет |
5.2.6. Приостановка и продолжение работы потока
Выполнение потока можно временно приостановить извне, а затем продолжить с помощью методов Suspend и Resume. Их вызовы могут быть вложенными. Прежде, чем процесс действительно продолжит работу, необходимо столько раз вызвать метод Resume, сколько раз до этого вызывался метод Suspend. Если необходимо проверить состояние потока (приостановлен или работает), используется свойство Suspended. Это свойство доступно по записи и может использоваться как альтернатива методам Suspend и Resume.
Прекращение работы потока. Для прекращения работы потока извне используется метод Terminate. Он устанавливает свойство Terminated в значение true, сигнализируя о том, что поток должен завершиться. Метод Execute должен периодически проверять свойство Terminated: если оно равно true, необходимо немедленно завершить выполнение метода. Завершение метода Execute прекращает работу потока и генерирует событие OnTerminate в главном потоке приложения. Событие OnTerminate позволяет приложению отреагировать на завершение своего потока и обычно обрабатывается формой. После завершения потока объект потока автоматически разрушается, если его свойство FreeOnTerminate установлено в значение true. Если свойство FreeOnTerminate равно false (устанавливается по умолчанию), разрушение объекта потока возложено на программиста.
Переменные, дублируемые для каждого нового потока. Все глобальные переменные, объявленные обычным образом в языке C++, разделяются всеми потоками приложения. Если же нужно получить глобальные переменные, дублируемые для каждого нового потока, следует использовать зарезервированное слово __thread, например:
int __thread a;
double __thread b, с;
В результате данного объявления для каждого нового потока будут создаваться копии переменных а, b, с. В результате каждый поток сможет использовать их в своих целях без всякой синхронизации с другими потоками.
Многопоточность в приложениях с БД. Использование многопоточности дает хороший результат при работе с БД SQL-типа. Если запрос к БД выполняется достаточно долго, то для этого лучше создать отдельный поток, предоставив пользователю возможность продолжить работу с другими данными.
Каждый поток, обращающийся к БД, должен иметь свой собственный компонент Session (а значит, собственные компоненты Query, Table и, если необходимо, Database). Не визуальный компонент Session как раз и существует для того, чтобы можно было создавать потоки, работающие с таблицами параллельно во времени. Кроме того, при работе с общими компонентами, объектами и функциями модуля данных должна быть обеспечена синхронизация потока с другими потоками, в том числе с главным потоком программы. Для этих целей служит метод Synchronize объекта TThread.
5.2.7. Пример реализации потока в С++ Builder 4
Приведем хорошо известный пример порядка действий программиста при создании многопоточного приложения, когда в одном потоке (главном) должен воспроизводиться видео-файл при помощи приложения MediaPlayer, в другом – происходить полет шарика [9].
Создаем новое приложение (New Application).
В ставляем приложение MediaPlayer. Оно находится во вкладке System (рис.46).
Рис.46
Вставляем компоненту Panel. Она будет являться дисплеем для MediaPlayer. Вставляем компоненту Timage для отображения действия с шариком. Подключаем пять кнопок Остановки воспроизведения, Воспроизведения, Открытия файла воспроизведения, Остановки параллельного потока и его запуска. Получим Диалог открытия файлов для открытия воспроизводимых файлов.
Расположение всех элементов на рабочем поле имеет вид (рис.47).
Р ис.47
О беспечим работу MediaPlayer и воспроизведение файлов. В окне «Object Inspector» (рис.48) в свойстве MediaPlayer Display нужно выставить Panel1. Тогда MediaPlayer будет отображать видео файлы на Panel1. Кроме того, следует установить на dtAutoSelect свойство Device Type для автоматического определения типов воспроизводимых файлов.
Рис.48
Чтобы по нажатию клавиши MediaPlayer воспроизводил файл, необходимо описать функцию для нажатия клавиши:
void __fastcall TForm1::MPStrBtnClick(TObject *Sender)
{
MediaPlayer1->Open();
MediaPlayer1->Play();
}
Функция Open() открывает файл, который хранится в свойстве MediaPlayer->FileName.
Функция Play() воспроизводит открытый Файл.
Так же опишем функцию для клавиши, по которой MediaPlayer остановит воспроизведение.
void __fastcall TForm1::MPStpBtnClick(TObject *Sender)
{
MediaPlayer1->Stop();
}
Аналогично описывается функция для открытия файла.
void __fastcall TForm1::MPOpnBtnClick(TObject *Sender)
{
if (OpenDialog1->Execute())
{
MediaPlayer1->FileName=OpenDialog1->FileName;
}
MediaPlayer1->Open();
}
Теперь MediaPlayer будет воспроизводить необходимые файлы, причем это будет производиться в главном потоке.
Обеспечим, чтобы в параллельном процессе обрабатывалось передвижение шарика. Для этого необходимо создать класс потока. В приведенной программе это класс Potok2.
Описания методов Synhr1 и Synhr2, а также метода Execute() даны в Приложении 3.
При анализе приведенного исходного кода стоит обратить внимание на следующие моменты. Конструктор объекта TMyThread создает приостановленный поток, вызывая унаследованный конструктор с параметром true (этот параметр называется Suspended). В результате поток создается, но работу еще не начинает. Это необходимо для исключения конфликтов между потоками при последующей инициализации полей объекта. Для запуска потока главная программа должна будет не только создать объект потока, но и установить его свойство Suspended в значение false.
Чтобы при завершении потока объект автоматически разрушался, конструктор устанавливает свойство FreeOnTerminate в значение true.
Для рисования шарика метод Execute использует вложенную рекурсивную функцию Shar. В теле этой функции выполняются периодические проверки свойства Terminated; если оно равно true, происходит немедленный выход из функции, возврат из рекурсии и завершение метода Execute.
Отображение Шарика требует обращения к совместно используемым объектам VCL. Для исключения конфликтов между потоками эти действия оформлены как методы Synhr1 и Synhr2, вызываемые с помощью метода Synchronize.