МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ «ЛЬВІВСЬКА ПОЛІТЕХНІКА»
/
ЗВІТ
до лабораторної роботи №4
з курсу:
«ОПЕРАЦІЙНІ СИСТЕМИ»
“ Багатопотокове програмування в сучасних ОС ”
Варіант № 12
Мета: ознайомлення з поняттям багатопотоковості в сучасних операційних системах, отримання практичних навичок створення багатопотокових застосувань в середовищі Visual Studio C#.
1. Теоретичні відомості
Як відомо [1] потоком (потік керування, нитка, thread) називають набір послідовно виконуваних команд процесора, які використовують загальний адресний простір процесу. Оскільки в системі може одночасно бути багато потоків, завданням ОС є організація перемикання процесора між ними і планування їхнього виконання. У багатопроцесорних системах код окремих потоків може виконуватися на окремих процесорах.
Багатопотоковими називають програми, які одночасно виконують різні чи однотипні завдання, використовуючи при тому декілька потоків.
Розглянемо яким чином можна оптимізувати програми, використовуючи багатопоточність.
Але не завжди можна розпаралелити задачу. Не завжди є в тому сенс. Наприклад, якщо у нас є один потік даних і його необхідно обробляти в певному порядку, і при цьому без результатів попередньої обробки даних наступну операцію виконувати не можна, то в такій програмі створення додаткових потоків нічого нам не дасть.
Потоки не повинні заважати один одному і повинні використовувати ефективно ресурси системи, в якій вони працюють.
Управління багатопотоковістю.
Управління багатопотоковістю здійснює планувальник потоків, цю функцію CLR зазвичай делегує операційній системі. Планувальник потоків гарантує, що активним потокам виділяється відповідний час на виконання, а потоки, які очікують або блоковані, наприклад, на очікуванні ексклюзивної блокування, або користувача введення - не споживають часу CPU.
На однопроцесорних комп'ютерах планувальник потоків використовує квантування часу - швидке перемикання між виконанням кожного з активних
2.
потоків. Це призводить до непередбачуваного поведінки, коли кожна послідовність виконання потоків відповідає кванту часу, виділеного потоку. У Windows XP типове значення кванта часу - десятки мілісекунд - вибрано як суттєво більшу, ніж витрати CPU на перемикання контексту між потоками (декілька мікросекунд).
На багатопроцесорних комп'ютерах багатопотоковість реалізована як комбінація квантування часу і справжнього паралелізму, коли різні потоки виконують код на різних CPU. Необхідність квантування часу все одно залишається, так як операційна система повинна обслуговувати як свої власні потоки, так і потоки інших додатків.
Кажуть, що потік витісняється, коли його виконання призупиняється через зовнішні фактори типу квантування часу. У більшості випадків потік не може контролювати, коли і де він буде витіснений.
Потоки і процеси.
Всі потоки однієї програми логічно містяться в межах процесу - модуля операційної системи, в якому виповнюється додаток.
У деяких аспектах потоки і процеси схожі - наприклад, час поділяється між процесами, що виконуються на одному комп'ютері, так само, як між потоками одного C #-додатки. Ключове відмінність полягає в тому, що процеси повністю ізольовані один від одного. Потоки поділяють пам'ять (купу) з іншими потоками цього ж додатка. Завдяки цьому один потік може постачати дані у фоновому режимі, а інший - показувати ці дані по мірі їх надходження.
Використання потоків.
Типовий додаток з багатопоточністю виконує тривалі обчислення у фоновому режимі. Головний потік продовжує виконання, в той час як робочий потік виконує фонову задачу. У додатках Windows Forms, коли головний потік зайнятий тривалими обчисленнями, він не може обробляти повідомлення клавіатури і миші, і додаток перестає відгукуватися. З цієї причини слід запускати віднімають багато часу завдання в робочому потоці, навіть якщо головний потік в цей час демонструє користувачеві модальний діалог з написом
3.
"Працюю ... Будь ласка, чекайте ", так як програма не може перейти до наступної операції, поки не закінчена поточна. Таке рішення гарантує, що програма не буде позначено операційною системою як "Не відповідає", спокушаючи користувача з горя прикінчити процес. Знову ж, у цьому випадку модальний діалог може надати кнопку "Скасувати", так як форма продовжує отримувати повідомлення, поки завдання виконується у фоновому потоці. Клас BackgroundWorker напевно стане в нагоді при реалізації такої моделі. У разі додатків без UI, наприклад, служб Windows, багатопотоковість має сенс, якщо виконувана завдання може зайняти багато часу, оскільки потрібно очікування відповіді від іншого комп'ютера (сервера додатків, сервера баз даних або клієнта). Запуск такого завдання в окремому робочому потоці означає, що головний потік негайно звільняється для інших завдань.
Інше застосування багатопотоковість знаходить в методах, що виконують інтенсивні обчислення. Такі методи можуть виконуватися швидше на багатопроцесорних комп'ютерах, якщо робоче навантаження рознесена по декількох потоках (кількість процесорів можна отримати через властивість Environment.ProcessorCount).
Додаток, створений на C # можна зробити багатопотоковим двома способами: або явно створюючи додаткові потоки і керуючи ними, або використовуючи можливості неявного створення потоків .NET Framework - BackgroundWorker, пул потоків, потоковий таймер, Remoting-сервер, Web-служби або додаток ASP.NET. У двох останніх випадках альтернативи багатопотоковості не існує. Однопотоковий web-сервер не просто поганий, він просто неможливий! На щастя, у випадку серверів додатків, що не зберігають стан (stateless), багатопотоковість реалізується зазвичай досить просто, складності можливі хіба що в синхронізації доступу до даних в статичних змінних.
Недоліки багатопотоковості.
Багатопотоковість разом з перевагами має і свої недоліки. Самий головний з них - значне збільшення складності програм. Складність збільшують не
4.
додаткові потоки самі по собі, а необхідність організації їх взаємодії. Від того, наскільки ця взаємодія є навмисною, залежить тривалість циклу розробки, а також кількість важко вловимих помилок у програмі. Таким чином, потрібно або підтримувати дизайн взаємодії потоків простим, або не використовувати багатопотоковість взагалі.
Крім того, надмірне використання багатопотоковості забирає ресурси і час CPU на створення потоків і перемикання між потоками. Зокрема, коли використовуються операції читання / запису на диск, більш швидким може виявитися послідовне виконання завдань в одному або двох потоках, ніж одночасне їх виконання в декількох потоках. Далі буде описана реалізація черги Постачальник / Споживач, що надає таку функціональність.
Засоби роботи з багатопотоковістю.
Для роботи з багатопотоковістю середовище .NET надає нам цілий простір імен System.Threading. У даному просторі імен міститься велика кількість різних типів. Для початку нам вистачить класу Thread, який якраз і знаходиться в даному просторі імен. У даного класу є багато корисних для роботи з потоками методів і властивостей, наприклад:
Start() - починає виконання потоку
Suspend() - призупиняє потік
Resume() - відновлює работу потоку
Priority – властивість, що визначає приорітет потоку
Для того що б почати працювати з потоками створимо в середовищі Visual Studio C# консольне застосування, підключимо простір імен System.Threading, додавши в початок файлу з кодом наступну директиву:
using System.Threading;
2. Завдання
Табл.1
№ вар.
Кількість потоків
Завдання
12
5
Добуток 2-х матриць (7х7).
5.
3. Текст програми
using System;
using System.Threading;
namespace ConsoleApplication8
{
class Program
{
#region Fields: Public
public static int column;
public static int row;
public static string matrixName;
#endregion
static void Main()
{
#region Inicialize Threads
Thread size1 = new Thread(new ParameterizedThreadStart(SetMatrixSize));
Thread value1 = new Thread(new ParameterizedThreadStart(SetMatrixValue));
Thread size2 = new Thread(new ParameterizedThreadStart(SetMatrixSize));
Thread value2 = new Thread(new ParameterizedThreadStart(SetMatrixValue));
Thread view = new Thread(new ParameterizedThreadStart(ViewMatrix));
size1.IsBackground = value2.IsBackground = size2.IsBackground = value2.IsBackground = view.IsBackground = false;
#endregion
#region Matrix №1 (Thread №1, Thread №2)
//Потік №1 - Визначення розмірів першої матриці
size1.Start("M1");
size1.Join();
Matrix M1 = new Matrix(row, column, matrixName);
//Потік №2 - Запис значень в першу матрицю
value1.Start(M1);
value1.Join();
#endregion
#region Matrix №2 (Thread №3, Thread №4)
//Потік №3 - Визначення розмірів другої матриці
size2.Start("M2");
size2.Join();
Matrix M2 = new Matrix(row, column, matrixName);
//Потік №4 - Запис значень в другу матрицю
value2.Start(M2);
value2.Join();
#endregion
#region Matrix №3 (Thread №5)
Matrix M3 = M2 * M1;
//Потік №5 - Вивід третьої матриці на консоль
view.Start(M3);
#endregion
}
#region STATIC VOID METHODS
public static void SetMatrixSize(object title)
{
Console.WriteLine("Введiть розмiр матрицi " + title + ":");
Console.Write("Рядки = ");
row = Convert.ToInt32(Console.ReadLine());
Console.Write("Стовпцi = ");
column = Convert.ToInt32(Console.ReadLine());
matrixName = title.ToString();
}
6.
public static void SetMatrixValue(object M)
{
Matrix.SetMatrixValue(M as Matrix);
}
public static void ViewMatrix(object M)
{
Matrix.ViewMatrix(M as Matrix);
}
#endregion
}
class Matrix
{
#region Indexator
public int this[int i, int j]
{
get { return Mass[i, j]; }
set { Mass[i, j] = value; }
}
#endregion
#region Properties
public int Column
{
get;
set;
}
public int Row
{
get;
set;
}
public int[,] Mass
{
get;
set;
}
public string Name
{
get;
set;
}
#endregion
#region Constructor
public Matrix(int row, int column, string name)
{
Column = column;
Row = row;
Name = name;
Mass = new int[row, column];
}
public Matrix(int row, int column)
{
Column = column;
Row = row;
Mass = new int[row, column];
Name = "M3";
}
#endregion
7.
#region Methods
public static Matrix SetMatrixValue(Matrix M)
{
for (int i = 0; i < M.Row; i++)
{
for (int j = 0; j < M.Column; j++)
{
Console.Write("" + M.Name + "[{0},{1}] = ", i, j);
M[i, j] = Convert.ToInt32(Console.ReadLine());
}
}
Console.WriteLine();
return M;
}
public static Matrix operator *(Matrix M1, Matrix M2)
{
Matrix M3 = new Matrix(M1.Row, M2.Column);
for (int i = 0; i < M1.Row; i++)
{
for (int k = 0; k < M2.Column; k++)
{
for (int j = 0; j < M1.Column; j++)
{
M3[i, k] += M1[i, j] * M2[j, k];
}
}
}
return M3;
}
public static void ViewMatrix(Matrix M)
{
Console.WriteLine("Значення матрицi " + M.Name + ":");
for (int i = 0; i < M.Column; i++)
{
for (int j = 0; j < M.Row; j++)
{
Console.Write("{0} ", M[i, j]);
}
Console.WriteLine();
}
Console.ReadLine();
}
#endregion
}
}
8.
4. Результат роботи програми
/ /
9.
/
Висновок: ознайомилась з поняттям багатопотоковості в сучасних операційних системах, отримала практичні навички створення багатопотокових застосувань в середовищі Visual Studio C#. Розробила програму для множення двох матриць із застосуванням багатопотоковості.
10.