Хід виконання роботи.
Приклад програми:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
//розмірність матриці
const int ROW = 20;
const int COL = 20;
// визначення матриці
float arr[ROW][COL];
// лічильник кількості рядків без від"ємних елементів
int k = 0;
HANDLE hChangeEvent, hCalcEvent;
DWORD WINAPI thread1 (LPVOID)
{
for (int i = 0; i < ROW; ++i)
{
// чекаємо поки другий потік надасть дозвіл на зміну рядка матриці
WaitForSingleObject(hChangeEvent, INFINITE); // закоментувати
// замінюємо від"ємні елементи їх квадратами
for (int j = 0; j < COL; ++j)
{
if (arr[i][j] < 0 )
arr[i][j] = arr[i][j]*arr[i][j];
Sleep(1);
}
// встановлення події - другому потоку можна рахувати від"ємні елементи
SetEvent(hCalcEvent); // закоментувати
}
return 0;
}
DWORD WINAPI thread2 (LPVOID)
{
for (int i = 0; i < ROW; ++i)
{
// чекаємо на завершення події зміни рядка матриці першим потоком
WaitForSingleObject(hCalcEvent, INFINITE); // закоментувати
// передивляємось рядок, чи є від"ємні елементи
bool IsAllPositive = true;
for (int j = 0; j < COL; ++j)
{
if (arr[i][j] < 0)
{
IsAllPositive = false;
break;
}
}
if (IsAllPositive)
++k;
// встановлення події - можна змінювати рядок матриці.
SetEvent(hChangeEvent); // закоментувати
}
return 0;
}
int main()
{
setlocale(LC_ALL, "");
HANDLE hThread1, hThread2;
DWORD IDThread;
// генерація матриці випадкових чисел
for (int i = 0; i < ROW; ++i)
for (int j = 0; j < COL; ++j)
arr[i][j] = rand()%50-25;
// створення подій
hChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
hCalcEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// створення потоків
hThread1 = CreateThread(NULL, 0, thread1, NULL, 0, &IDThread);
if (hThread1 == NULL)
return GetLastError();
hThread2 = CreateThread(NULL, 0, thread2, NULL, 0, &IDThread);
if (hThread2 == NULL)
return GetLastError();
// Запускаємо перший потік
SetEvent(hChangeEvent);
// очікування завершення потоків
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
cout << "\nПотоки синхронiзовано\n";
cout << "\nКiлькiсть рядкiв без вiд\"ємних елементiв\n"
<< "(пiдрахунок у паралельному потоцi) k = " << k << endl;
// закриття дескрипторів потоків
CloseHandle(hThread1);
CloseHandle(hThread2);
CloseHandle(hChangeEvent);
CloseHandle(hCalcEvent);
return 0;
}
Щоб запустити програму без синхронізації потоків потрібно за коментувати позначені рядки.
Результат роботи програми:
До використання синхронізації:
З використанням об’єктів синхронізації:
Пояснення: Кожен потік по рядках переглядає матрицю.
В першому варіанті (без синхронізації) виконання потоку thread1 переривається потоком thread2. Тому thread1 не встигає пройти повністю рядок матриці та замінити всі від’ємні елементи квадратами. В свою чергу, потік thread2 «бачить» у рядку незмінені від’ємні елементи та не змінює лічильник k.
В другому варіанті (з синхронізацією) кожен потік чекає своєї черги на обробку рядка матриці (функція WaitForSingleObject) та передає управління іншому потоку (функція SetEvent) тільки після завершення своєї роботи.
