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

ЛР1_вар1 _Программирование параллельных процессов

.docx
Скачиваний:
10
Добавлен:
18.01.2022
Размер:
268.17 Кб
Скачать

МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ федеральное государственное автономное образовательное учреждение высшего образования

«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ

АЭРОКОСМИЧЕСКОГО ПРИБОРОСТРОЕНИЯ»

ИНСТИТУТ НЕПРЕРЫВНОГО И ДИСТАНЦИОННОГО ОБРАЗОВАНИЯ

КАФЕДРА ВЫЧИСЛИТЕЛЬНЫХ СИСТЕМ И СЕТЕЙ

ОЦЕНКА

ПРЕПОДАВАТЕЛЬ

кандидат технических наук, доцент

Кучин Н.В.

должность, уч. степень, звание

подпись, дата

инициалы, фамилия

ОТЧЕТ О ЛАБОРАТОРНОЙ РАБОТЕ №1

Программирование параллельных процессов

по дисциплине: Операционные системы

РАБОТУ ВЫПОЛНИЛА

СТУДЕНТКА ГР. №

номер группы

подпись, дата

инициалы, фамилия

Санкт-Петербург 2021

Цель работы

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

Задание для варианта №1

Рисунок 1 – Задание варианта

Имя задачи

Длительность

Приоритет

Функция

A

1

0

Генерирует М[1..n, 1..n],

R [ 1..n ] - boolean

B

1

1

f1 (M, R)

C

1

1

f2 (M, R)

D

1

1

f3 (M, R)

E

1

2

f4(f1, f2, f3)

F

2

3

f5(f1, f2, f3)

G

1

3

f6(f4)

H

1

3

f7(f4)

K

1

4

f8(f5, f6, f7)

Таблица №1 – Задание варианта

Описание используемых методов

Описание методов, используемых в программе, можно увидеть в Таблице №2.

Название

Описание

Form1

Метод, инициализирующий окно программы.

DoIt_Click

Метод, обрабатывающий нажатие на кнопку запуска программы. Запускает поток ThrA(TaskA).

ClearLogBtn_Click

Метод, стирающий лог выполнения программы.

LogText

Метод, пишущий в лог программы текст, переданный первым аргументом.

ThreadInfoHandler

Метод, пишущий в лог информацию о запуске потока, и возвращающий текущее время, в миллисекундах с 01.01.1970 0:00:00

ThreadExitHandler

Метод, пишущий в лог информацию об окончании потока, а так же его время выполнения и окончания.

Timestamp

Метод, возвращающий текущее время, в миллисекундах с 01.01.1970 0:00:00

ProgressUp

Метод, который обновляет значение прогресс-бара и текстовое значение процента завершённых задач.

RRand

Метод, генератора массива булевых значений.

ArrayRand

Метод, генератора массива значений.

F1

Функция f1. Итерирует массив M1 итератором i и j. Если значение R[i] == true, то добавляет M[i] в сумму sum, иначе – из этой суммы значение вычитает.

F2

Функция f2. Итерирует массив M1 итератором i и j. Если значение R[i] == false, то задаёт sum = M1[i] – i*3, иначе – из этой суммы вычитает M1[i] + i*2.

F3

Функция f3. Итерирует массив M1 итератором i. В int sum добавляет значение M1[i], и в зависимости от значения M2[i], либо добавляет, либо вычитает 7.

F4

Функция f4. Вычисляет значение ((f1+f2)*f3)

F5

Функция f5. Вычисляет значение (f1+(f2*f3))

F6

Функция f5. Вычисляет квадратный корень из f4

F7

Вычисляет значение f4+10

F8

Вычисляет значение f5+(f6+f7)^2

TaskA

Поток А. Наполняет массив M1 при помощи метода ArrayRand. Для синхронизации использует lock()

TaskB

Поток B. Наполняет массив R1при помощи метода RRand. Для синхронизации использует lock()

TaskC

Поток C. Наполняет массив R2 при помощи метода RRand. Для синхронизации использует lock()

TaskD

Поток D. Вычисляет значение f1, и запускает поток G. Для синхронизации использует lock()

TaskE

Поток E. Вычисляет значение f2, и, и запускает поток G.

TaskF

Поток F. Вычисляет значение f3, и, если поток G и поток H уже завершены, запускает поток K.

TaskG

Поток G. Вычисляет значение f4, и, если поток H и поток F уже завершены, запускает поток K.

TaskH

Поток H. Вычисляет значение f5, и, если поток G и поток F уже завершены, запускает поток K.

TaskK

Поток K. Вычисляет значение f6

Таблица №2 – Описание используемых методов

Протокол выполения задач

Протокол выполнения задач программы можно увидеть на Рисунке №2.

Рисунок 2 – Протокол выполнения задач

Динамика выполнения задач

Динамика выполнения задач отображается при помощи индикатора выполнения ProgressBar, и текстового отображения процента всех выполненных задач через элемент Label, что видно на Рисунках 3 и 4.

Рисунок 3 – Индикатор и процент выполнения при пяти выполненных задачах

Рисунок 4- Индикатор и процент выполнения при девяти (всех) выполненных задачах

Выводы

Выполнив работу, я научился разрабатывать программы, реализующие параллельное выполнение нескольких задач, каждая из которых решает некоторую заданную функцию.

ПРИЛОЖЕНИЕ №1

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using System.Windows.Forms;

namespace labOS

{

public partial class Form1 : Form

{

//Ядра

Thread ThrA;

Thread ThrB;

Thread ThrC;

Thread ThrD;

Thread ThrE;

Thread ThrF;

Thread ThrG;

Thread ThrH;

Thread ThrK;

//объект локер

static object locker = new object();

//Время начала работы

long ExecStartTime;

//Количество завершенных заданий

int FinishedTasks;

//Результаты выполенения функций

int F1_res;

int F2_res;

int F3_res;

int F4_res;

int F5_res;

int F6_res;

int[,] M1 = new int[5,5];

bool[] R1 = new bool[5];

bool[] R2 = new bool[5];

/*******Графика**********/

public Form1()

{

InitializeComponent();

}

//Обработчик клика на кнопку, запускает тред А

private void DoIt_Click(object sender, EventArgs e)

{

FinishedTasks = 0;

progressBar1.Value = 0;

//Задаём время начала выполения

ExecStartTime = Timestamp();

LogText("----------------");

//Создаём тред А

ThrA = new Thread(new ThreadStart(TaskA));

ThrA.Start();

ThrB = new Thread(new ThreadStart(TaskB));

ThrB.Start();

ThrC = new Thread(new ThreadStart(TaskC));

ThrC.Start();

}

//Обработчик клика кнопки очищения лога

private void ClearLogBtn_Click(object sender, EventArgs e)

{

log.Text = "";

}

//--------

//Методы-утилиты

//--------

//Инициализация генератора булевых значений

Random rng = new Random();

public void RRand(bool[] R)

{

for (int i = 0; i < R.Length; i++)

{

R[i] = (rng.Next(100) > 50);

}

}

public void ArrayRand(int[,] array)

{

int rows = array.GetUpperBound(0) + 1; // количество строк

int columns = array.Length / rows; // количество столбцов

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

{

for (int j = 0; j < columns; j++)

{

array[i, j] = rng.Next(100);

}

}

}

//Функция для вывода данных на экран

public void LogText(String what)

{

//Если вызов из треда, инвокаем в гуй

if (InvokeRequired)

{

this.Invoke(new Action<string>(LogText), new object[] { what });

return;

}

String pre = "\r\n";

if (log.Text == "")

{

pre = "";

}

log.Text += pre + what.ToString();

}

//Выводит информацию при запуске треда, так же возвращает время в миллисекундах

public long ThreadInfoHandler(String ActiveThread, String ParentThread)

{

LogText("[" + ActiveThread + "] Тред " + ActiveThread + " запущен тредом " + ParentThread + " в " + (Timestamp() - ExecStartTime).ToString() + " мс");

return Timestamp();

}

//Выводит информацию при окончании треда, выводит время выполения треда в миллисекундах, увеличивает значение прогресс-бара

public void ThreadExitHandler(String ActiveThread, long StartTime)

{

//Если вызов из треда, инвокаем в гуй

if (InvokeRequired)

{

this.Invoke(new Action<string, long>(ThreadExitHandler), new object[] { ActiveThread, StartTime });

return;

}

ProgressUp(true);

//Подсчитываем время исполения

long NowTime = Timestamp();

String ExecTime = (NowTime - StartTime).ToString();

LogText("[" + ActiveThread + "] Тред " + ActiveThread + " завершился, время выполения: " + ExecTime + "ms, время окончания - " + (NowTime - ExecStartTime).ToString() + " ms\r\n");

}

//Обновляет прогресс-бар и процентное отношение завершения

public void ProgressUp(bool UpdateText = true)

{

//Если вызов из треда, инвокаем в гуй

if (InvokeRequired)

{

this.Invoke(new Action<bool>(ProgressUp), new object[] { UpdateText });

return;

}

FinishedTasks += 1;

progressBar1.Value = FinishedTasks;

if (UpdateText)

{

ProgessPercent.Text = ((float)FinishedTasks / 9 * 100).ToString() + " %";

}

}

//Время в миллисекундах юних

public long Timestamp()

{

return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

}

//--------

//Функции

//--------

//Функция f1

public int F1(int[,] array, bool[] R1, bool[] R2)

{

int rows = array.GetUpperBound(0) + 1; // количество строк

int columns = array.Length / rows; // количество столбцов

int Sum = 0;

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

{

for (int j = 0; j < columns; j++)

{

if ((R1[i])&(R2[j]))

{

Sum += array[i, j];

}

}

}

return Sum;

}

//Функция f2

public int F2(int[,] array, bool[] R1, bool[] R2)

{

int rows = array.GetUpperBound(0) + 1; // количество строк

int columns = array.Length / rows; // количество столбцов

int P = 1;

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

{

for (int j = 0; j < columns; j++)

{

if ((R1[i]) & (R2[j]))

{

P *= array[i, j];

}

}

}

return P;

}

//Функция f3

public int F3(int[,] array, bool[] R1, bool[] R2)

{

int rows = array.GetUpperBound(0) + 1; // количество строк

int columns = array.Length / rows; // количество столбцов

int Sum = 0;

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

{

for (int j = 0; j < columns; j++)

{

if ((!R1[i]) & (!R2[j]))

{

Sum += array[i, j];

}

}

}

return Sum;

}

//Функция f4

public int F4(int f1)

{

int Q = f1 * 2;

return Q;

}

//Функция f5

public int F5(int f2)

{

int W = f2 + 100;

return W;

}

//Функция f6

public int F6(int f3, int f4, int f5)

{

int E = (f3 + f4) * f5;

return E;

}

//--------

//Задачи

//--------

//Задача A

public void TaskA()

{

long startTime = ThreadInfoHandler("A", "UI-тред");

//Ждём секунду, как требуется в варианте

System.Threading.Thread.Sleep(1000);

LogText("Генерируем значения двумерного массива M1 ");

lock(M1)

{

ArrayRand(M1);

}

LogText("M1 сгенерирован");

ThreadExitHandler("A", startTime);

lock (ThrB)

{

lock (ThrC)

{

if ((!ThrB.IsAlive)&(!ThrC.IsAlive))

{

ThrD = new Thread(() => TaskD("А"));

ThrD.Start();

ThrE = new Thread(() => TaskE("А"));

ThrE.Start();

ThrF = new Thread(() => TaskF("А"));

ThrF.Start();

}

}

}

}

//Задача B

public void TaskB()

{

long startTime = ThreadInfoHandler("B", "UI-тред");

//Ждём секунду, как требуется в варианте

System.Threading.Thread.Sleep(1000);

LogText("Генерируем значение R1");

lock(R1)

{

RRand(R1);

}

LogText("R1 сгенерирован");

ThreadExitHandler("B", startTime);

lock (ThrA)

{

lock (ThrC)

{

if ((!ThrA.IsAlive) & (!ThrC.IsAlive))

{

ThrD = new Thread(() => TaskD("B"));

ThrD.Start();

ThrE = new Thread(() => TaskE("B"));

ThrE.Start();

ThrF = new Thread(() => TaskF("B"));

ThrF.Start();

}

}

}

}

//Задача C

public void TaskC()

{

long startTime = ThreadInfoHandler("C", "UI-тред");

//Ждём секунду, как требуется в варианте

System.Threading.Thread.Sleep(1000);

LogText("Генерируем значение R2");

lock (R2)

{

RRand(R2);

}

LogText("R1 сгенерирован");

ThreadExitHandler("C", startTime);

lock (ThrA)

{

lock (ThrB)

{

if ((!ThrA.IsAlive) & (!ThrB.IsAlive))

{

ThrD = new Thread(() => TaskD("C"));

ThrD.Start();

ThrE = new Thread(() => TaskE("C"));

ThrE.Start();

ThrF = new Thread(() => TaskF("C"));

ThrF.Start();

}

}

}

}

//Задача D

public void TaskD(String ParentThread)

{

long startTime = ThreadInfoHandler("D", ParentThread);

//Ждём секунду, как требуется в варианте

System.Threading.Thread.Sleep(1000);

LogText("[D] Исполняем функцию f1");

lock (M1)

{

lock (R1)

{

lock (R2)

{

F1_res = F1(M1, R1, R2);

}

}

}

LogText("[D] Значение F1: " + F1_res.ToString());

ThreadExitHandler("D", startTime);

//Запускаем тред G

ThrG = new Thread(() => TaskG("D"));

ThrG.Start();

}

//Задача E

public void TaskE(String ParentThread)

{

long startTime = ThreadInfoHandler("E", ParentThread);

//Ждём 2 секунды, как требуется в варианте

System.Threading.Thread.Sleep(1000);

LogText("[E] Исполняем функцию f2");

lock (M1)

{

lock (R1)

{

lock (R2)

{

F2_res = F2(M1, R1, R2);

}

}

}

LogText("[E] Значение F2: " + F2_res.ToString());

ThreadExitHandler("E", startTime);

//Запускаем тред H

ThrH = new Thread(() => TaskH("E"));

ThrH.Start();

}

//Задача F

public void TaskF(String ParentThread)

{

long startTime = ThreadInfoHandler("F", ParentThread);

//Ждём 2 секунды, как требуется в варианте

System.Threading.Thread.Sleep(2000);

LogText("[F] Исполняем функцию f3");

lock (M1)

{

lock (R1)

{

lock (R2)

{

F3_res = F3(M1, R1, R2);

}

}

}

LogText("[F] Значение F3: " + F3_res.ToString());

ThreadExitHandler("F", startTime);

lock (ThrH)

{

lock (ThrG)

{

if ((!ThrG.IsAlive) & (!ThrH.IsAlive))

{

ThrK = new Thread(() => TaskK("F"));

ThrK.Start();

}

}

}

}

//Задача G

public void TaskG(String ParentThread)

{

long startTime = ThreadInfoHandler("G", ParentThread);

//Ждём секунду, как требуется в варианте

System.Threading.Thread.Sleep(1000);

LogText("[G] Исполняем функцию f4");

F4_res = F4(F1_res);

LogText("[G] Значение F4: " + F4_res.ToString());

ThreadExitHandler("G", startTime);

lock (ThrH)

{

lock (ThrF)

{

if ((!ThrF.IsAlive) & (!ThrH.IsAlive))

{

ThrK = new Thread(() => TaskK("G"));

ThrK.Start();

}

}

}

}

//Задача H

public void TaskH(String ParentThread)

{

long startTime = ThreadInfoHandler("H", ParentThread);

//Ждём 1 секунды, как требуется в варианте

System.Threading.Thread.Sleep(1000);

LogText("[H] Исполняем функцию f5");

F5_res = F5(F2_res);

LogText("[H] Значение F5: " + F5_res.ToString());

ThreadExitHandler("H", startTime);

lock (ThrG)

{

lock (ThrF)

{

if ((!ThrF.IsAlive) & (!ThrG.IsAlive))

{

ThrK = new Thread(() => TaskK("H"));

ThrK.Start();

}

}

}

}

//Задача K

public void TaskK(String ParentThread)

{

long startTime = ThreadInfoHandler("K", ParentThread);

//Ждём 1 секундy, как требуется в варианте

System.Threading.Thread.Sleep(1000);

LogText("[H] Исполняем функцию f6");

F6_res = F6(F3_res, F4_res, F5_res);

LogText("[H] Значение F6: " + F6_res.ToString());

ThreadExitHandler("K", startTime);

}

}

}