
Лаб. 6 ТПП
.docxЛабораторная работа №6
Замки и барьеры
Цель: изучить основные особенности использования барьеров и замков в OpenMP на примере использования в рамках языка С++.
Пример:
Задание 1:
#include <iostream>
#include <omp.h>
#include <iomanip>
const int N = 100;
using namespace std;
int main() {
setlocale(LC_ALL, "Rus");
cout << "N: " << N << endl << endl;
int i;
int* a = new int[N];
int* b = new int[N];
int* c = new int[N];
srand(static_cast<unsigned int>(time(nullptr)));
for (i = 0; i < N; i++)
a[i] = rand() % 21 - 10;
for (i = 0; i < N; i++)
b[i] = rand() % 21 - 10;
double start_time = omp_get_wtime();
long total = 0;
omp_lock_t lock;
omp_init_lock(&lock); // Инициализация семафора
#pragma omp parallel num_threads(3) shared(a, b, c, total, lock)
{
#pragma omp for private(i)
for (i = 0; i < N; i++) {
if (a[i] > b[i])
c[i] = a[i];
else
c[i] = b[i];
// Использование семафора для обновления общей переменной
omp_set_lock(&lock);
total += c[i];
omp_unset_lock(&lock);
}
}
omp_destroy_lock(&lock); // Освобождение семафора
double end_time = omp_get_wtime();
//cout << "Задание 1:" << endl;
cout << "Замки" << endl;
cout << "Итоговая сумма: " << total << endl;
cout << "Время выполнения: " << fixed << setprecision(16) << (end_time - start_time) << " секунд" << endl;
double start_time_r = omp_get_wtime();
long total_r = 0;
#pragma omp parallel num_threads(3) shared(a,b,c) reduction(+:total_r)
{
#pragma omp for private(i)
for (i = 0; i < N; i++)
{
if (a[i] > b[i])
c[i] = a[i];
else
c[i] = b[i];
total_r += c[i];
}
}
double end_time_r = omp_get_wtime();
cout << "reduction" << endl;
cout << "Итоговая сумма: " << total_r << endl;
cout << "Время выполнения: " << fixed << setprecision(16) << (end_time_r - start_time_r) << " секунд" << endl;
delete[] a;
delete[] b;
delete[] c;
return 0;
}
Тратится время на выполнение операций установки и снятия замка. Если один поток удерживает замок, то другие потоки должны ждать, что тоже занимает время.
#include <iostream>
#include <omp.h>
#include <iomanip>
const int N = 1000;
using namespace std;
int main()
{
setlocale(LC_ALL, "Rus");
cout << "N: " << N << endl << endl;
int i;
int* a = new int[N];
int* b = new int[N];
int* c = new int[N];
srand(static_cast<unsigned int>(time(nullptr)));
for (i = 0; i < N; i++)
a[i] = rand() % 21 - 10;
for (i = 0; i < N; i++)
b[i] = rand() % 21 - 10;
double start_time = omp_get_wtime();
long total = 0;
#pragma omp parallel num_threads(3) shared(a, b, c) reduction(+:total)
{
#pragma omp for nowait private(i)
for (i = 0; i < N; i++)
{
if (a[i] > b[i])
c[i] = a[i];
else
c[i] = b[i];
//total += c[i];
}
#pragma omp for private(i)
for (i = 0; i < N; i++)
{
total += c[i];
}
}
double end_time = omp_get_wtime();
cout << "Без барьерной синхронизации" << endl;
cout << "Итоговая сумма: " << total << endl;
cout << "Время выполнения: " << fixed << setprecision(16) << (end_time - start_time) << " секунд" << endl;
total = 0;
start_time = omp_get_wtime();
#pragma omp parallel num_threads(3) shared(a, b, c) reduction(+:total)
{
int thread_id = omp_get_thread_num();
#pragma omp for nowait private(i)
for (i = 0; i < N; i++)
{
if (a[i] > b[i])
c[i] = a[i];
else
c[i] = b[i];
//total += c[i];
}
#pragma omp barrier
printf("Поток %d дошёл до барьера\n", thread_id);
#pragma omp for private(i)
for (i = 0; i < N; i++)
{
total += c[i];
}
}
end_time = omp_get_wtime();
cout << "С барьерной синхронизацией" << endl;
cout << "Итоговая сумма: " << total << endl;
cout << "Время выполнения: " << fixed << setprecision(16) << (end_time - start_time) << " секунд" << endl;
delete[] a;
delete[] b;
delete[] c;
return 0;
}
Директива nowait позволяет избежать барьерной синхронизации после выполнения конструкций: for, sections, single.
#include <iostream>
#include <omp.h>
#include <iomanip>
const int N = 100;
using namespace std;
int main()
{
setlocale(LC_ALL, "Rus");
cout << "N: " << N << endl << endl;
int i;
int* a = new int[N];
int* b = new int[N];
int* c = new int[N];
srand(static_cast<unsigned int>(time(nullptr)));
for (i = 0; i < N; i++)
a[i] = rand() % 21 - 10;
for (i = 0; i < N; i++)
b[i] = rand() % 21 - 10;
double start_time = omp_get_wtime();
long total = 0;
#pragma omp parallel num_threads(3) shared(a, b, c) reduction(+:total)
{
#pragma omp for private(i)
for (i = 0; i < N; i++)
{
if (a[i] > b[i])
c[i] = a[i];
else
c[i] = b[i];
total += c[i];
}
}
double end_time = omp_get_wtime();
cout << "Без барьерной синхронизации" << endl;
cout << "Итоговая сумма: " << total << endl;
cout << "Время выполнения: " << fixed << setprecision(16) << (end_time - start_time) << " секунд" << endl;
total = 0;
start_time = omp_get_wtime();
#pragma omp parallel num_threads(3) shared(a, b, c) reduction(+:total)
{
int thread_id = omp_get_thread_num();
#pragma omp for private(i)
for (i = 0; i < N; i++)
{
if (a[i] > b[i])
c[i] = a[i];
else
c[i] = b[i];
total += c[i];
}
#pragma omp barrier
//#pragma omp single
// {
// cout << "Все потоки завершили вычисления." << endl;
printf("Поток %d дошёл до барьера\n", thread_id);
// }
}
end_time = omp_get_wtime();
cout << "С барьерной синхронизацией" << endl;
cout << "Итоговая сумма: " << total << endl;
cout << "Время выполнения: " << fixed << setprecision(16) << (end_time - start_time) << " секунд" << endl;
delete[] a;
delete[] b;
delete[] c;
return 0;
}