Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

методички / 4045 ЭИ

.pdf
Скачиваний:
33
Добавлен:
14.05.2019
Размер:
1.16 Mб
Скачать

Лабораторная работа № 3

УПРАВЛЕНИЕ ПАРАЛЛЕЛЬНЫМИ ПОТОКАМИ, СВЯЗАННЫМИ СИНХРОНИЗАЦИЕЙ НА ОСНОВЕ СОБЫТИЙ

Цель работы: на основании базового примера программного кода ознакомиться с последовательностью действий объявления, выполнения и деструкции параллельных связанных потоков.

Задание

1.Загрузить архив демонстрационной программы «Многопоточность. Связанные синхронизируемые потоки. Асинхронное взаимодействие с VCL» [3.4], распаковать, запустить программу под Ubutu и ознакомиться с порядком взаимодействия потоков через событие синхронизации.

2.Создать и отладить код программы работы синхронизированных событием пото-

ков.

3.Выполнить задание организации действий в процедурах потоков по варианту преподавателя.

Ход работы

Ознакомиться с примерами-заданиями по разработке параллельных потоков с асинхронным выводом и связанными по управлению событиями. Выбрать по желанию язык программирования. На основании примеров решить задачу с достижением поставленной

вработе цели.

1.Пример-задание «Многомерные связанные потоки – описание основных классов (Lazarus)», приложение 3, П3.1. Основные данные и процедуры: класс коллекции потоков; модификация класса списка потоков, которую следует рассмотреть как пример использования полиформизма в технологиях ООП при связанном запуске и остановке потоков.

2.Пример-задание «Многомерные потоки – организация взаимодействия и синхронного управления (Lazarus)», приложение 3, П3.2. Основная форма размещения интерфейсных элементов управления списком потоков и каждым потоком в отдельности на основании событий синхронизации действий.

Результат работы

Выполняемый модуль программы с решением задачи внутри коллекции потоков. Тип задачи определяется персональным заданием преподавателя для каждого студента.

Содержание отчета

Отлаженный модуль программы с выполненным заданием

11

Контрольные вопросы

1.Концепция семафоров в управлении синхронизированными потоками.

2.Характеристики объекта события.

3.Работа объекта события как двухпозиционного ключа, основные типы сигналов событий.

БИБЛИОГРАФИЧЕСКИЙ СПИСОК

Основной

1.Молчанов А. Ю. Системное программное обеспечение: учеб. для вузов. – СПб.: Питер, 2013.

2.Таненбаум Э. Современные операционные системы / пер. с англ. – 2-е изд. – СПб:

Питер, 2003. – 1.1040 с.: ил.

3.Вильямс А. Системное программирование в Windows 2000 для профессионалов – СПб: Питер, 2003. – 624 с.: ил.

Интернет-ресурсы

1.http://www.delphisources.ru/pages/faq/base/threads_development.html

2.http://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm

Загрузка примеров

1.http://rostradesamara.ru/gups/01/1/load/1459520588896/1459520609208/

threadmono.zip

2.http://rostrade-samara.ru/gups/01/1/load/1459520588896/1459520609208/ threadcollectVCL.zip

3.http://inf.samgups.org.ru/gups/01/1/load/1459520588896/1459520609208/thread.zip

4.http://rostrade-samara.ru/gups/01/1/load/1459520588896/1459520609208/ threadLinkCollec.zip

12

Приложение 1

ОДНОМЕРНЫЕ ПОТОКИ

П1.1. Одномерный поток Delphi/Lazarus

Ознакомиться с примером, создать форму. По событию кнопки создать поток и выполнить задание преподавателя по действию потока над данными (процедура DoWork).

Модуль проекта

program project1;

{$mode objfpc}{$H+}

//Добавить для программ работы с потоками

{$DEFINE UNIX} {$DEFINE UseCThreads}

//=====

uses

{$IFDEF UNIX}{$IFDEF UseCThreads} cthreads,

{$ENDIF}{$ENDIF}

Interfaces, // this includes the LCL widgetset Forms, Unit1, Unit2;

{$R *.res}

begin

RequireDerivedFormResource := True; Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run;

end.

Модуль класса потока

{Модуль объекта потока, поток выполняет действия с интервалом, указанным для sleep()}

unit Unit2;

{$mode objfpc}{$H+} interface

uses

Classes, SysUtils,Dialogs;

const CThreadPriority: array[0..6] of TThreadPriority = ( tpTimeCritical, // Приоритет реального времени tpHighest,

tpHigher,

tpNormal,

tpLower,

tpLowest,

tpIdle // процесс выполняется только тогда, когда система не занята

);

{Определение класса TMyThread} type

TMyThread = class(TThread) public

mdelay: integer; // время паузы

procedure DoWork;virtual;abstract; // процедура потока

13

Приложение 1

constructor Create(CreateSuspended: Boolean); private

{ Private declarations } protected

procedure Execute; override; end;

implementation

constructor TMyThread.Create(CreateSuspended: Boolean); begin

inherited Create(CreateSuspended);

{Если FreeOnTerminate имеет значение True, то VCL автоматически разрушает объект потока при его завершении}

FreeOnTerminate := false; // Объект будет разрушаться программно // для получения признака not Assigned()

Priority := CThreadPriority[3]; // тип приоритета - нормальный mdelay := 1000; // задержка «по умолчанию» 1 сек

end;

procedure TMyThread.Execute; begin

// Циклический вызов потока while not Terminated do begin

sleep(mdelay); Synchronize(@DoWork);

end;

end;

end.

Пример наследования потока и создание экземпляра потока

type

{ TForm1 }

// Создаем наследника потока для работы с формой

TIncDecData = class(TMyThread) public

incdata: integer; // изменяемое значение sleep() sign: boolean; // знак инкремента

procedure DoWork;override; // процедура потока constructor Create(CreateSuspended: Boolean);

private protected end;

implementation {$R *.lfm}

constructor TIncDecData.Create(CreateSuspended: Boolean); begin

inherited Create(CreateSuspended); incdata := 0;

sign := true; end;

// Основная процедура потока procedure TIncDecData.DoWork;

14

Приложение 1

begin Form1.lbInc.Caption:=intToStr(incdata);

if (sign) then // инкремент с учетом знака inc(incdata)

else dec(incdata);

end;

// Например, используя событие формы (кнопка «Старт»), создаем и запускаем поток

tread := TIncDecData.Create(true); tread.Start;

П1.2. Одномерный поток: CodeBlock C++. Настройки компилятора

Подготовка компилятора работе

1.Создать пустой проект для консольного приложения С++

2.На файловой панели проекта (Projects) правой кнопкой мыши вызвать контекстное меню и выбрать пункт «Build options...». Прописать опцию -pthread на закладках настройки компилятора и компоновщика (рис. П1.1, П1.2).

Рис. П1.1. Настройки компилятора

3. В окно основного файла проекта main.cpp вписать следующий текст:

#include <pthread.h> // модуль потока

15

Приложение 1

#include <stdio.h> #include <stdlib.h>

#include <unistd.h> // sleep(1)

void *myThreadFun(void *vargp) // Рабочая функция потока

{

sleep(1); // задержка на 1 сек. printf(«Printing hi from Thread \n»); // оператор в потоке return NULL;

}

 

int main()

 

{

 

pthread_t tid;

// переменная типа «поток»

printf(«Before Thread\n»); // сообщение до инициализации потока pthread_create(&tid, NULL, myThreadFun, NULL); // создать поток с рабочей функцией

pthread_join(tid, NULL);

// включить выполнение функции myThreadFun в потоке tid

printf(«After Thread\n»);

// сообщение после завершения потока

exit(0); // Завершение работы программы

}

Рис. П1.2. Настройки компановщика

16

Приложение 1

4. Построить приложение (F9) с выводом результата потока на экран

Ознакомиться с примером программы. Выполнить задание преподавателя по действию потока, изменив код функции myThreadFun.

П1.3. Одномерный поток MonoDevelop C#

Подготовка проекта к работе

1.Создать пустой проект для консольного приложения C#

2.Пример № 1. В окно основного файла проекта Program.cs поочередно вписать текст следующих примеров:

using System;

using System.Threading; // Это пространство имен поддерживает многопоточность

/* Пример одномерного потока.

Программа поочередно выводит сообщения потока и стандартного вывода с консоли, демонстрируя асинхронную независимость консоли и потока */

namespace ConsoleApplication1

{

class Program

{

// Функция запускается из потока static void func()

{

for (int i = 0; i < 10; i++) {

Console.WriteLine («Поток выводит « + i.ToString ()); Thread.Sleep (0); // Минимальная задержка в потоке

}

}

static void Main(string[] args)

{

Thread myThread = new Thread(func); //Создаем новый объект потока (Thread) myThread.Start(); // Запускаем поток

for (int i = 0; i < 10; i++ )

{

Console.WriteLine(«Консоль выводит « + i);

Thread.Sleep(0); // Минимальная задержка консольного вывода

}

Console.Read(); // Останов в ожидании нажатия клавиши myThread.Join(); // Удалить поток

}

}

}

3.Пример № 2.

using System;

using System.Threading;

// Демонстрационный пример организации одномерного потока public class Worker

{

// This method will be called when the thread is started. public void DoWork() // Процедура потока

{

17

Приложение 1

while (!_shouldStop)

{

Console.WriteLine(«worker thread: working...»);

}

Console.WriteLine(«worker thread: terminating gracefully.»);

}

public void RequestStop()

{

_shouldStop = true; // установка переменной завершения цикла

}

//Volatile is used as hint to the compiler that this data

//member will be accessed by multiple threads. private volatile bool _shouldStop;

}

public class WorkerThreadExample

{

static void Main()

{

//Create the thread object. This does not start the thread. Worker workerObject = new Worker();

//передача в поток основной процедуры

Thread workerThread = new Thread(workerObject.DoWork);

// Start the worker thread.

workerThread.Start(); // запуск процедуры в потоке Console.WriteLine(«main thread: Starting worker thread...»);

//Loop until worker thread activates. //while (!workerThread.IsAlive);

//Put the main thread to sleep for 1 millisecond to

//allow the worker thread to do some work: Thread.Sleep(1); // «Время» работы потока

//Request that the worker thread stop itself: workerObject.RequestStop();

//Use the Join method to block the current thread

//until the object's thread terminates. workerThread.Join(); // Удаление потока

Console.WriteLine(«main thread: Worker thread has terminated.»);

}

}

4. Для каждого из примеров построить приложение (Ctrl-F5) с выводом результата потока на экран

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

18

Приложение 2

МНОГОМЕРНЫЕ ПОТОКИ

П2.1. Описание основных классов в программе (Lazarus)

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

Главный модуль проекта

program project1; {$mode objfpc}{$H+}

//Добавить для программ работы с потоками (тестировалось для i386)

{$DEFINE UNIX} {$DEFINE UseCThreads}

//=====

uses

{$IFDEF UNIX}{$IFDEF UseCThreads} cthreads,

{$ENDIF}{$ENDIF}

Interfaces, // this includes the LCL widgetset Forms, Unit1

{ you can add units after this };

{$R *.res}

begin

RequireDerivedFormResource := True; Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run;

end.

Модуль классов потока и списка ссылок на поток. Основная работа потока - «продвигать» линию статуса до завершения большого цикла. Для вывода в главный поток используется синхронизация (Synchronize), вызываемая не на каждой итерации действия, а через значительный интервал для уменьшения побочного эффекта синхронизации вывода. Список учета потока наследуется от TthreadList с возможностью блокировки при изменении данных относительно ссылки на поток. Также добавлена процедура для полиморфного вызова деструктора потока при проходе по списку с последующей его очисткой Clear.

{Независимый процесс-поток; коллекция-лист объектов потока} unit Unit2;

{$mode objfpc}{$H+}

interface

uses

Classes, SysUtils,Dialogs,STDCTRLS,ComCtrls;

const

CThreadPriority: array[0..6] of TThreadPriority = ( tpTimeCritical, // Приоритет реального времени

19

Приложение 2

tpHighest,

 

tpHigher,

 

tpNormal,

// Приоритет по умолчанию

tpLower,

 

tpLowest,

tpIdle // процесс выполняется только тогда, когда система не занята

);

{Класс независимого потока TMyThread} type

TMyThread = class(TThread) private

FCounter: Integer; // Переменные ProgressBar FCountTo: Integer;

PctDone: Extended; Interval: integer;

progbar: TProgressBar; // VCL - линия прогресса

mesLabel: TLabel;

// VCL - Процент выполнения

mRep: TMemo;

// Отчет процессов по завершению

StartTime,EndTime: TDateTime;

procedure DoWork;

// процедура потока связи с VCL

public

ID: integer; // Идентификатор потока pause: boolean; // Приостановка потока function getPriority(pri: TThreadPriority): string; Procedure Report; // Отчет по заверщению Procedure starTHread; // Запуск процесса

Procedure setPriory(set_: integer); // Установка приоритета constructor Create(Suspended_: Boolean; id_:integer;

priory: integer; progbar_: TProgressBar; mesLabel_: TLabel; mem_: TMemo);

protected

procedure Execute; override; // Процедура потока end;

{Класс блокируемой коллекции потоков TCollthreadlist}

TCollthreadlist = class(tthreadlist)

procedure ClearThread; // Clear коллекции с деструкцией объектов потока

Destructor Destroy; end;

implementation

{TCollthreadlist}

Destructor TCollthreadlist.Destroy; begin

ClearThread; inherited Destroy;

end;

procedure TCollthreadlist.ClearThread; var i: integer;

begin

for i:=0 to self.LockList.Count-1 do // Проход по коллекции Tthread(LockList.Items[i]).Destroy; // Освобождение ресурса

self.LockList.Clear;

end;

20

Соседние файлы в папке методички