Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Задание5.doc
Скачиваний:
5
Добавлен:
13.11.2019
Размер:
516.1 Кб
Скачать

10

ЗАДАНИЕ

на лабораторное занятие № 5

Исследование средств коммуникации процессов

Цели работы: 1. Исследовать возможности ОС Windows и ИС Delphi по синхронизации и коммуникации процессов.

2. Закрепить практические навыки по работе в интегрированной среде программирования Delphi.

1. Задание на лабораторное занятие

1.1. Разработать, отладить и выполнить на ПЭВМ программу создания нескольких потоков, управления взаимодействием их с объектами ОС и синхронизации между собой.

1.2. Исследовать взаимодействие потоков при различных исходных условиях и внешних воздействиях.

2. Подготовка к работе

Подготовка к работе проводится в часы самоподготовки.

В ходе её каждый студент обязан:

2.1. Изучить настоящее задание.

2.2. Повторить материал занятий, на которых рассматривались:

– понятия процесса и потока, назначение и состав дескриптора процесса;

– средства ИС Delphi для программирования потоков и процессов;

– порядок создания приложений, состоящих из нескольких модулей.

2.3. Повторить порядок работы в интегрированной среде Delphi.

3. Методические указания

3.1. В классе ПЭВМ студенты самостоятельно под руководством преподавателя выполняют п. 4 настоящего задания. Студенты, которые успешно справились с основным заданием (пп. 4.1-4.3), завершили оформление отчета о работе и представили его для проверки преподавателю, допускаются к выполнению дополнительного задания (п. 4.4).

3.2. При разработке программы следует использовать стан­дартный класс TThread. Объект, создаваемый на основе этого класса, можно охарактеризовать следующими свойствами:

– каждый поток имеет свою, при необходимости уникальную, исполняемую часть;

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

– диспетчеризация выполнения потоков осуществляется операционной системой и не требует вмешательства программиста;

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

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

3.4. Текст отлаженной программы (с комментариями) необходимо занести в конспект.

4. Выполнение работы

4.1. Постановка задачи

Необходимо создать многопоточное приложение, схема взаимодейст­вия отдельных потоков в котором (в рамках единого вычислительного процесса) приведена на рис. 1.

Рис. 1. Схема взаимодействия параллельно выполняющихся задач

Согласно этому рисунку, процесс А после своего завершения запускает зада­чи D, С и Е. Будем считать, что задачи В, D и С завершаются примерно в одинаковое время. По крайней мере, не известно, какой из потоков должен быть первым, а какой – последним. Пусть поток F будет запус­каться тем из перечисленных потоков, который завершается первым, но только после того, как завершатся два оставшихся потока, приходящие в “точку синхро­низации”. Наконец, пусть задача G запускается последним закончившим работу потоком Е или F.

Все указанные задачи создадим как потомки объекта TThread. Поскольку действия, выполняемые задачами, для нас не имеют значения, ис­полняемую часть можно представить простейшим циклом с соответствующей задержкой. Для нагляд­ности внутри цикла можно организовать вывод текущего состояния выполнения задачи в процентах на “строке состояния”, для чего используется компонент TGauge. Все семь потоков похожи (используют одни и те же методы) и отличаются только в части принятия решения о синхронизации.

Базовый объект (TTreadProgress) является потомком объекта TTread. При этом он имеет следующие поля:

– имя потока;

– строка состояния потока;

– “длина” потока (время его работы в отсутствие конкурентов);

– текущее состояние потока;

– признак завершения потока;

– имя запустившего потока;

– строка для вывода сообщений в компонент TMemo.

В базовом объекте объявлены следующие процедуры:

– исполняемая часть;

– завершающая часть;

– процедура прорисовки строки состояния;

– процедура вывода сообщения;

– конструктор объекта,

Все потоки (от А до G) являются потомками этого объекта и перекрывают един­ственный метод – процедуру завершения процесса. В исполняемой части задачи после завершения цикла задержки, имитирующего выполнение полезной рабо­ты, устанавливается признак завершения и вызывается процедура завершения задачи, которая и выполняет соответствующие действия.

Общую схему работы программы, реализующей задание, можно описать следую­щим образом. Все задачи инициализируются соответствующей процедурой од­новременно, но в режиме ожидания запуска. В качестве параметров инициализа­ции в создаваемый поток передаются его имя, длительность и имя запускающего объекта (если оно известно заранее). Сразу после инициализации запускаются задачи А и В. Обе задачи сигнализируют об этом соответствующим сообщением. После своего завершения поток А запускает задачи (потоки) С, D и Е. Далее все идет в соответствии с заданной блок-схемой. Задача, запускающая другую зада­чу, передает ей свое имя, обращаясь непосредственно к полю этого объекта. Ин­формацию о том, завершился тот или иной поток, можно получить, обратившись к соответствующему полю – признаку завершения задачи.

Естественно, что при подобной организации доступа к полям потоков вероятно возникновение разного рода критических ситуаций. Напомним, основная причи­на их возникновения заключена в том, что несколько задач (в нашем случае – потоков) реально имеют возможность обращения к общим ресурсам практиче­ски одновременно, то есть с таким интервалом времени, за который этот ресурс не успеет изменить свое состояние. В результате задачи могут получать некор­ректные значения, о чем мы уже немало говорили.

Каждый процесс имеет связь с так называемыми VCL-объектами – видимыми компонентами. В данном случае такими являются строка состояния TGauge и поле сообщений TMemo. Для того чтобы в процессе работы нескольких парал­лельно выполняющихся задач не возникало критических ситуаций с выводом информации на эти видимые на экране объекты, к ним необходимо обеспечить синхронизированный доступ. Это довольно легко достигается с помощью стан­дартного для объекта TThread метода Synchronize. Метод имеет в качестве пара­метра имя процедуры, в которой производится вывод на VCL-объекты. При этом сама эта процедура нигде в программе не должна вызываться напрямую без ис­пользования метода Synchronize. В нашей программе такими процедурами явля­ются прорисовка строки состояния (DoVisualProgress) и вывод текстового сообщения (WriteToMemo). Подобное использование метода Synchronize обес­печивает корректную работу нескольких параллельных процессов с VCL-объек­тами.

Однако метод Synchronize не помогает в случае совместного доступа к другим общим ресурсам. Поэтому необходимо применять другие средства для организа­ции взаимного исключения. Главная цель этих средств заключается в обеспече­нии монопольного доступа для каждой задачи к общим ресурсам, то есть пока один поток не закончил обращение к подобному ресурсу, другой не имеет право этот ресурс использовать.

В системе программирования Delphi для этой цели имеется довольно-таки про­стой в использовании и достаточно эффективный метод критической секции с помощью объекта TCriticalSection. Этот метод заключается в следующем:

– участок кода каждого потока, в котором производится обращение к общему ресурсу, заключается в “скобки” критической секции – используются мето­ды Enter и Leave;

– если какой-либо поток уже находится внутри критической секции, то другой поток, который дошел до “открывающей скобки” Enter, не имеет права вхо­дить в критическую секцию до тех пор, пока первый поток находится в ней. Когда первый поток выйдет из критической секции, второй сможет войти в нее и, в свою очередь, обратиться к критическому ресурсу.

Очевидно, что такой метод надежно обеспечивает задачам монопольный доступ к общим (критическим) ресурсам.

Метод критической секции имеет ряд преимуществ перед его аналогами. Так, например, использование семафоров (Semaphore) сложнее в реализации. Другой метод взаимных исключений – mutex – в целом похож на метод критической секции, но он требует больше системных ресурсов и имеет свое время тайм-аута, по истечении которого ожидающий процесс может все-таки войти в защищен­ный блок, в то время как в критической секции подобного механизма нет.