Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторные работы / Лабораторная работа 3 / Умножение двух матриц методом статического разделения на полосы (Захаров).docx
Скачиваний:
32
Добавлен:
28.06.2014
Размер:
148.39 Кб
Скачать

Приложение. Код программы.

// Отключение предупреждений безопасности

#define _CRT_SECURE_NO_WARNINGS

#define _CRT_SECURE_NO_DEPRECATE

#define _CRT_NONSTDC_NO_DEPRECATE

// Коды ошибок

#define E_THREAD_ALLOC 1

#define E_THREAD_CREATE 2

#include <windows.h>

#include <tchar.h>

#include <strsafe.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <errno.h>

#include <time.h>

#include <stdarg.h>

#include <math.h>

// --- Настройки программы ---

// Включение режима отладки

// #define DEBUG

// Число запусков теста

#define TEST_COUNT 5

// --- Настройки потоков ---

// Ограничения на число потоков

#define MIN_THREADS 1

#define MAX_THREADS 12

int gen_random(float, float);

int matrix_create(const char*, int, int);

void print_log(const char*, ...);

void print_err(const char*);

DWORD WINAPI MyThreadFunction(LPVOID lpParam);

// Структура данных потока

typedef struct ThreadData {

int i; // Номер потока

} TDATA, *PTDATA;

int **A;

int **B;

int **C;

// Размерности матриц А{mxn}, B{nxq}, C{mxq}

int n = 20000, m = 20000, q = 20000;

// Пути к файлам исходных данных и результата

const char *A_path = "A.txt"; FILE *Astream;

const char *B_path = "B.txt"; FILE *Bstream;

const char *C_path = "C.txt"; FILE *Cstream;

const char *L_path = "lab.log"; FILE *Lstream;

// Числа строк матрицы A, обрабатываемые потоками

int Arows[MAX_THREADS];

// Номера строк матрицы A, обрабатываемые потоками

int Nrows[MAX_THREADS];

int _tmain()

{

srand((UINT32) time(NULL));

int i, j, h, d;

// Время выполнения каждого из запусков программы

double time[TEST_COUNT];

PTDATA pDataArray[MAX_THREADS];

DWORD dwThreadIdArray[MAX_THREADS];

HANDLE hThreadArray[MAX_THREADS];

// Запускаем программу для 1, 2, ..., MAX_THREADS потоков

for(int threads = MIN_THREADS; threads <= MAX_THREADS; threads++)

{

// Запускаем тест TEST_COUNT раз

for(h = 0; h < TEST_COUNT; h++)

{

// Фиксируем время начала работы программы

time[h] = (double) clock();

// Пытаемся открыть файлы с матрицами A и B

Astream = fopen(A_path, "r");

Bstream = fopen(B_path, "r");

// Обработка ошибок при открытии файлов

if(Astream == NULL || Bstream == NULL)

{

if((Astream != NULL && fclose(Astream)) || (Bstream != NULL && fclose(Bstream)))

{

print_log("[ERROR] Не удалось закрыть один из исходных файлов");

return 0;

}

// Генереция новых файлов с матрицами A и B

if(!matrix_create(A_path, m, n) || !matrix_create(B_path, n, q))

{

print_log("[ERROR] Не удалось сгенерировать матрицы A и B");

return 0;

}

// Не учитываем время, затраченное на генерацию матриц

time[h] = (double) clock();

Astream = fopen(A_path, "r");

Bstream = fopen(B_path, "r");

if(Astream == NULL || Bstream == NULL)

{

print_log("[ERROR] Не удалось сгенерировать матрицы A и B");

return 0;

}

}

// Считываем размерности матриц

if(fscanf(Astream, "%d %d\n", &m, &n) <= 0 || fscanf(Bstream, "%d %d\n", &d, &q) <= 0)

{

print_log("[ERROR] Не удалось считать размерности матриц");

fclose(Astream);

fclose(Bstream);

return 0;

}

if(n != d || n <= 0 || m <= 0 || q <= 0)

{

if(n != d)

print_log("[ERROR] Не верно заданы размерности матриц:

Число столбцов в матрице A не совпадает с числом строк в матрице B");

if(n <= 0 || m <= 0 || q <= 0)

print_log("[ERROR] Не верно заданы размерности матриц:

Размерность не может быть меньше либо равна нулю");

fclose(Astream);

fclose(Bstream);

return 0;

}

// Делим строки матрицы A между потоками

d = (int) floor(double(m / threads));

for(i = 0; i < threads; i++)

{

Arows[i] = d;

Nrows[i] = i * d;

}

d = m % threads;

for(i = 0; d != 0; d--)

{

Arows[i]++;

for(j = i + 1; j < threads; j++)

Nrows[j]++;

i = (i < threads) ? i + 1 : 0;

}

// Запись информации о группе тестов в лог-файл

if(!h)

{

time[h] = (double) clock() - time[h];

if(threads == MIN_THREADS)

print_log("----------------------------------------------\n

Размерности матриц m=%d n=%d q=%d\n\n", m, n, q);

print_log("Число потоков %d\n\n", threads);

print_log("[DEBUG] Распределение строк матрицы A между потоками:\n{");

for(i = 0; i < threads - 1; i++)

print_log("%d (%d), ", Arows[i], Nrows[i]);

print_log("%d (%d)}\n\n", Arows[threads - 1], Nrows[threads - 1]);

time[h] = (double) clock() - time[h];

}

// Выделение памяти

A = (int **) malloc(m * sizeof(int *));

B = (int **) malloc(n * sizeof(int *));

C = (int **) malloc(m * sizeof(int *));

if(A == NULL || B == NULL || C == NULL)

{

print_err("Не удалось выделить память");

fclose(Astream);

fclose(Bstream);

if(A != NULL) free(A);

if(B != NULL) free(B);

if(C != NULL) free(C);

return 0;

}

for(i = 0; i < m; i++)

{

A[i] = (int *) malloc(n * sizeof(int));

C[i] = (int *) malloc(q * sizeof(int));

if(A[i] == NULL || C[i] == NULL)

{

print_err("Не удалось выделить память");

fclose(Astream);

fclose(Bstream);

free(A); free(B); free(C);

return 0;

}

}

for(i = 0; i < n; i++)

{

B[i] = (int *) malloc(q * sizeof(int));

if(B[i] == NULL)

{

print_err("Не удалось выделить память");

fclose(Astream);

fclose(Bstream);

free(A); free(B); free(C);

return 0;

}

}

// Чтение матрицы A

for(i = 0; i < m; i++)

{

for(j = 0; j < n; j++)

{

if(fscanf(Astream, "%d", &A[i][j]) <= 0)

{

print_err("Не удалось считать элемент матрицы A");

fclose(Astream);

fclose(Bstream);

free(A); free(B); free(C);

return 0;

}

}

}

fclose(Astream);

// Чтение матрицы B

for(i = 0; i < n; i++)

{

for(j = 0; j < q; j++)

{

if(fscanf(Bstream, "%d", &B[i][j]) <= 0)

{

print_err("Не удалось считать элемент матрицы B");

fclose(Bstream);

free(A); free(B); free(C);

return 0;

}

}

}

fclose(Bstream);

// Обнуление результирующей матрицы C

for(i = 0; i < m; i++)

for(j = 0; j < q; j++)

C[i][j] = 0;

for(i = 0; i < threads; i++)

{

// Выделяем память для потока

pDataArray[i] = (PTDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TDATA));

// Если не удалось выделить память, то прерываем выполнение программы

if(pDataArray[i] == NULL)

{

print_log("[ERROR] Не удалось выделить память для потока\n");

free(A); free(B); free(C);

ExitProcess(E_THREAD_ALLOC);

}

pDataArray[i]->i = i;

// Создаём поток

hThreadArray[i] = CreateThread(

NULL, // атрибуты безопасности по умолчанию

0, // используем размер стека по умолчанию

MyThreadFunction, // имя функции потока

pDataArray[i], // аргумент функции потока

0, // используем стандартные флаги

&dwThreadIdArray[i] // получаем идентификатор потока

);

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

if(hThreadArray[i] == NULL)

{

ExitProcess(E_THREAD_CREATE);

}

}

// Ждём, пока не выполнятся все потоки

WaitForMultipleObjects(threads, hThreadArray, TRUE, INFINITE);

// Закрываем все дескрипторы потоков и освобождаем выделенную память

for(i = 0; i < threads; i++)

{

CloseHandle(hThreadArray[i]);

if(pDataArray[i] != NULL)

{

HeapFree(GetProcessHeap(), 0, pDataArray[i]);

pDataArray[i] = NULL;

}

}

free(A);

free(B);

// Записываем результат в файл

Cstream = fopen(C_path, "w");

if (Cstream == NULL)

{

print_err("Не удалось создать файл для произведения матриц");

return 0;

}

for(i = 0; i < m; i++)

{

for(j = 0; j < q - 1; j++)

{

if(fprintf(Cstream, "%d ", C[i][j]) < 0)

{

fclose(Cstream);

return 0;

}

}

if(fprintf(Cstream, "%d\n", C[i][q - 1]) < 0)

{

fclose(Cstream);

return 0;

}

}

free(C);

if(fclose(Cstream))

{

print_err("Не удалось закрыть поток");

return 0;

}

// Записываем время в лог-файл

time[h] = ((double) clock() - time[h]) / CLOCKS_PER_SEC;

print_log("Время (%d): %f сек\n", h + 1, time[h]);

}

// Записываем среднее время в лог-файл

time[0] = time[0] / TEST_COUNT;

for(i = 1; i < TEST_COUNT; i++)

time[0] += time[i] / TEST_COUNT;

print_log("Среднее : %f сек\n\n", time[0]);

}

return 0;

}

DWORD WINAPI MyThreadFunction(LPVOID lpData)

{

PTDATA data = (PTDATA) lpData;

int t = data->i;

int first = Nrows[t];

int last = first + Arows[t];

int i, j, k;

for(i = 0; i < n; i++)

{

for(j = first; j < last; j++)

{

for(k = 0; k < q; k++)

{

C[j][k] += A[j][i] * B[i][k];

}

}

}

return 0;

}

// Генерирует псевдо-случайное число из интервала

// a - левая граница интервала

// b - правая граница интервала

// Возвращает сгенерированное число из интервала из интервала [a;b]

int gen_random(float a, float b)

{

return (int) (a + (b - a) * ((float)rand() / RAND_MAX));

}

// Генерирует файл с матрицей mхn

// path - путь к файлу (например, имя файла или абсолютный путь к файлу)

// m - число строк в матрице

// n - число столбцов в матрице

// Возвращает 1, если матрица успешно создана. В случае ошибки возвращает 0 и записывает сообщение в лог.

int matrix_create(const char *path, int m, int n)

{

if(n <= 0 || m <= 0)

{

print_log("[ERROR] Не удалось сгенерировать файл с матрицей: Не верно задана размерность матрицы\n");

return 0;

}

FILE *stream = fopen(path, "w");

if(stream == NULL)

{

print_err("Не удалось создать файл для матрицы");

return 0;

}

// Записываем размерность матрицы

fprintf(stream, "%d %d\n", m, n);

// Генерируем матрицу

int i, j;

for(i = 0; i < m; i++)

{

for(j = 0; j < n - 1; j++)

fprintf(stream, "%d ", gen_random(-10, 10));

fprintf(stream, "%d\n", gen_random(-10, 10));

}

if(fclose(stream))

{

print_err("Не удалось закрыть поток");

return 0;

}

return 1;

}

// Записывает сообщение message в лог

void print_log(const char *message, ...)

{

va_list ptr;

va_start(ptr, message);

// Открываем файл логов

FILE *stream = fopen(L_path, "a");

if(stream == NULL)

return;

// Записываем сообщение в лог

vfprintf(stream, message, ptr);

fclose(stream);

va_end(ptr);

}

// Выводит сообщение по коду ошибки errno

// message - необязательное дополнительное описание ошибки

void print_err(const char *message)

{

char *msg = (char *)"[ERROR] ";

if(message != NULL)

msg = strcat(msg, message);

switch(errno)

{

case E2BIG : msg = strcat(msg, "Список аргументов слишком длинный"); break;

case EACCES : msg = strcat(msg, "Отказ в доступе"); break;

case EADDRINUSE : msg = strcat(msg, "Адрес используется"); break;

case EADDRNOTAVAIL : msg = strcat(msg, "Адрес недоступен"); break;

case EAFNOSUPPORT : msg = strcat(msg, "Семейство адресов не поддерживается"); break;

case EALREADY : msg = strcat(msg, "Соединение уже устанавливается"); break;

case EBADF : msg = strcat(msg, "Неправильный дескриптор файла"); break;

// ...

default : msg = strcat(msg, "Неизвестная ошибка");

}

print_log(msg);

}

1 Среднее арифметическое по результатам 5 измерений

2 Среднее арифметическое по результатам 5 измерений

Москва, 2012