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

лабораторные Тимофеев / 3316_Кирейкова_Лабораторная3

.pdf
Скачиваний:
0
Добавлен:
01.06.2026
Размер:
623.08 Кб
Скачать

МИНОБРНАУКИ РОССИИ

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

ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ

«ЛЭТИ» ИМ. В.И. УЛЬЯНОВА (ЛЕНИНА)

Кафедра Вычислительной техники

ОТЧЕТ

по лабораторной работе №3 по дисциплине «Операционные системы»

Тема: Процессы и потоки

Выполнила: Кирейкова С.А. Группа: 3316 Преподаватель Тимофеев А.В

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

2025

Цель работы

Исследовать механизмы создания и управления процессами и потоками в

ОС Windows.

Задание 3.1. Реализация многопоточного приложения с использованием функций Win32 API.

Указания к выполнению.

1. Создайте приложение, которое вычисляет число pi с точностью

N знаков после запятой по следующей формуле, где N=100000000.

Используйте распределение итераций блоками (размер блока = 10

*Nстуд. билета) по потокам. Сначала каждый поток по очереди получает свой блок итераций, затем тот поток, который заканчивает выполнение своего блока, получает следующий свободный блок итераций. Освободившиеся потоки получают новые блоки итераций до тех пор, пока все блоки не будут исчерпаны.

Создание потоков выполняйте с помощью функции Win32 API CreateThread.

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

По окончании обработки текущего блока итераций поток не должен завершаться, а должен быть, например, приостановлен с помощью функции Win32 API SuspendThread. Затем потоку должен быть предоставлен следующий свободный блок итераций, и поток должен быть освобожден, например, с помощью функции Win32 API

2

ResumeThread.

2. Произведите замеры времени выполнения приложения для разного числа потоков (1, 2, 4, 8, 12, 16). По результатам измерений

2 постройте график и определите число потоков, при котором достигается наибольшая скорость выполнения. Запротоколируйте результаты в отчет.

3. Подготовьте итоговый отчет с развернутыми выводами по заданию.

Пример выполнения программы:

Код программы

#include <windows.h> #include <iostream> #include <iomanip> #include <chrono> #include <mutex>

using namespace std; const int N = 100000000;

const int BLOCK_SIZE = 10 * 331611; const int MAX_THREADS = 16;

double pi = 0.0;

int current_block = 0; HANDLE block_mutex; HANDLE pi_mutex;

DWORD WINAPI ThreadFunction(LPVOID lpParam) { while (true) { int block_start, block_end;

WaitForSingleObject(block_mutex, INFINITE);

if (current_block * BLOCK_SIZE >= N) { ReleaseMutex(block_mutex); break;

}

block_start = current_block * BLOCK_SIZE; current_block++; ReleaseMutex(block_mutex);

block_end = min(block_start + BLOCK_SIZE, N); double partial_sum = 0.0; for (int i = block_start; i<block_end; i++) {

partial_sum += (4 / (1 + (((long double)i + 0.5) / (long double)N)*(((long double)i + 0.5) / (long double)N)));

}

3

WaitForSingleObject(pi_mutex, INFINITE); pi += partial_sum; ReleaseMutex(pi_mutex);

}

return 0;

}

void Calculation(int num_threads) { pi = 0.0; current_block = 0;

block_mutex = CreateMutex(NULL, FALSE, NULL); pi_mutex = CreateMutex(NULL, FALSE, NULL);

HANDLE threads[MAX_THREADS];

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

threads[i] = CreateThread(NULL, 0, ThreadFunction, NULL, 0, NULL); if (threads[i] == NULL) {

cerr<< "Error creating thread " <<i<< endl; return;

}

}

auto start = chrono::high_resolution_clock::now(); WaitForMultipleObjects(num_threads, threads, TRUE, INFINITE); auto end = chrono::high_resolution_clock::now();

auto duration = chrono::duration_cast<chrono::milliseconds>(end - start);

for (int i = 0; i<num_threads; i++) { CloseHandle(threads[i]);

}

CloseHandle(block_mutex); CloseHandle(pi_mutex);

pi /= N;

cout<< "Threads: " <<num_threads

<<"\tTime: " <<duration.count() << " ms"

<<"\tPi: " <<setprecision(15) << pi <<endl;

}

int main() {

cout<< "Calculating Pi with " << N << " iterations\n"; cout<< "Block size: " << BLOCK_SIZE << " \n";

int thread_counts[] = {1, 2, 4, 8, 12, 16}; for (int count :thread_counts) { Calculation(count);

}

return 0;

}

График зависимости времени вычисления от количества потоков

4

Выводы по первой части

В ходе выполнения первой части лабораторной работы было разработано приложение для многопоточного вычисления числа π по заданной формуле. Для реализации параллельных вычислений использовались функции Win32 API: CreateThread для создания потоков и CreateMutex для организации синхронизации. Управление доступом к разделяемым данным обеспечивалось через механизм мьютексов: поток с помощью WaitForSingleObject получал доступ, выполнял вычисление своей части выражения и затем освобождал ресурс.

После завершения работы всех потоков результаты суммировались и нормировались по числу итераций.

Анализ графика показал выраженную обратную зависимость между временем

5

выполнения и количеством потоков. На промежутке от 1 до 4 потоков наблюдается значительное ускорение, однако при дальнейшем увеличении количество потоков оказывает всё меньшее влияние на итоговое время. Разница между 12 и 16 потоками практически отсутствует, что связано с накладными расходами на создание и управление потоками, а также блокировку и разблокировку мьютексов. При 8 потоках зафиксирован небольшой рост времени,

который можно объяснить дополнительными издержками синхронизации и возможным неравномерным распределением блоков итераций.

Таким образом, было показано, что использование многопоточности действительно повышает эффективность вычислений, однако чрезмерное увеличение числа потоков не всегда приводит к улучшению производительности из-за накладных расходов.

6

Задание 3.2. Реализация многопоточного приложения с использованием технологии OpenMP.

Указания к выполнению.

1. Создайте приложение, которое вычисляет число пи с точностью

N знаков после запятой по следующей формуле

где N=100000000.

Распределите работу по потокам с помощью OpenMP-директивы

for.

Используйте динамическое планирование блоками итераций (размер блока = 10 * Nстудбилета).

2.Произведите замеры времени выполнения приложения для разного числа потоков (1, 2, 4, 8, 12, 16). По результатам измерений

постройте график и определите число потоков, при котором достигается наибольшая скорость выполнения. Запротоколируйте результаты в отчет, сравните с результатами прошлой работы.

3.Подготовьте итоговый отчет с развернутыми выводами по заданию.

Пример выполнения программы:

7

Код программы

#include <iostream> #include <iomanip> #include <chrono> #include <omp.h>

using namespace std;

const

size_t

N = 100000000;

// общее количество итераций

const

size_t

BLOCKSIZE = 10

* 331612; // размер блока

long double PI_calculation(size_t Iterations, int Threads) { long double pi_sum = 0.0;

#pragma omp parallel for reduction(+:pi_sum) schedule(dynamic, BLOCKSIZE) num_threads(Threads)

for (size_t i = 0; i < Iterations; i++) {

long double x = (static_cast<long double>(i) + 0.5L) / Iterations; pi_sum += 4.0L / (1.0L + x * x);

}

return pi_sum / Iterations;

}

int main() {

int threadsNumber[] = {1, 2, 4, 8, 12, 16};

int arraySize = sizeof(threadsNumber) / sizeof(threadsNumber[0]);

cout << "\nOpenMP\n";

cout << "Total iterations: " << N << "\n";

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

auto start = chrono::high_resolution_clock::now();

long double piValue = PI_calculation(N, threadsNumber[i]); auto end = chrono::high_resolution_clock::now();

auto duration = chrono::duration_cast<chrono::milliseconds>(end - start);

cout << "Threads: " << threadsNumber[i]

<<"\tTime: " << duration.count() << " ms"

<<"\tPi: " << setprecision(15) << piValue << "\n";

}

8

return 0;

}

9

График зависимости времени вычисления от количества потоков

Вывод:

В ходе работы реализовано параллельное вычисление числа π с

использованием OpenMP. Применение директив parallel for и reduction

позволило эффективно распределить вычисления между потоками.

Наблюдалось ускорение при увеличении числа потоков от 1 до 4. После оптимизации компиляции время выполнения сократилось с 400 мс до 350 мс.

Результаты подтвердили эффективность OpenMP для параллельных вычислений: библиотека обеспечивает простой синтаксис при автоматическом управлении потоками и позволяет достигать существенного прироста производительности.

10