I essentially took this progam, and made it compile and run on Windows too. Also, I incorporated some nice points made by Toby Speight.
matrix.h
#ifndef NET_CODERODDE_LINEAR_ALGEBRA_MATRIX_H
#define NET_CODERODDE_LINEAR_ALGEBRA_MATRIX_H
#include <stdlib.h>
typedef struct matrix_t {
size_t m_rows;
size_t m_cols;
double* m_data;
} matrix_t;
matrix_t* matrix_t_alloc (const size_t rows, const size_t cols);
void matrix_t_init (matrix_t* matrix, size_t rows, size_t cols);
void matrix_t_clear (matrix_t* matrix);
void matrix_t_free (matrix_t* matrix);
double matrix_t_get (matrix_t* matrix, size_t x, size_t y);
void matrix_t_set (matrix_t* matrix, size_t x, size_t y, double value);
matrix_t* matrix_t_copy (matrix_t* matrix);
#endif /* NET_CODERODDE_LINEAR_ALGEBRA_MATRIX_H */#pragma once
matrix_algorithm.h
#ifndef NET_CODERODDE_LINEAR_ALGEBRA_MATRIX_ALGORITHM_H
#define NET_CODERODDE_LINEAR_ALGEBRA_MATRIX_ALGORITHM_H
#include "matrix.h"
matrix_t* matrix_t_multiply(matrix_t* matrix1, matrix_t* matrix2);
matrix_t* matrix_t_multiply_parallel(matrix_t* matrix1, matrix_t* matrix2);
void matrix_t_print(matrix_t* matrix);
size_t get_number_of_processors();
#endif /* NET_CODERODDE_LINEAR_ALGEBRA_MATRIX_ALGORITHM_H */
matrix.c
#include "matrix.h"
#include <stdlib.h>
#include <string.h>
static size_t data_index(matrix_t* matrix, size_t x, size_t y)
{
return y * matrix->m_cols + x;
}
matrix_t* matrix_t_alloc(size_t rows, size_t cols)
{
matrix_t* m = malloc(sizeof *m);
if (!m)
{
return m;
}
matrix_t_init(m, rows, cols);
if (!m->m_data)
{
free(m);
return NULL;
}
return m;
}
void matrix_t_init(matrix_t* matrix, size_t rows, size_t cols)
{
matrix->m_data = malloc(sizeof *matrix->m_data * rows * cols);
if (matrix->m_data)
{
matrix->m_rows = rows;
matrix->m_cols = cols;
}
else
{
matrix->m_rows = 0;
matrix->m_cols = 0;
}
}
void matrix_t_clear(matrix_t* matrix)
{
free(matrix->m_data);
matrix->m_rows = 0;
matrix->m_cols = 0;
}
void matrix_t_free(matrix_t* matrix)
{
matrix_t_clear(matrix);
free(matrix);
}
double matrix_t_get(matrix_t* matrix, size_t x, size_t y)
{
return matrix->m_data[data_index(matrix, x, y)];
}
void matrix_t_set(matrix_t* matrix, size_t x, size_t y, double value)
{
matrix->m_data[data_index(matrix, x, y)] = value;
}
matrix_t* matrix_t_copy(matrix_t* matrix)
{
size_t data_len = sizeof(double) * matrix->m_rows * matrix->m_cols;
matrix_t* copy = malloc(sizeof(*copy));
copy->m_rows = matrix->m_rows;
copy->m_cols = matrix->m_cols;
copy->m_data = malloc(data_len);
memcpy(copy->m_data, matrix->m_data, data_len);
return copy;
}
matrix_algorithm.c
#include "matrix.h"
#include "matrix_algorithm.h"
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#endif
static size_t max_size_t(size_t x, size_t y)
{
return x > y ? x : y;
}
static size_t min_size_t(size_t x, size_t y)
{
return x < y ? x : y;
}
size_t get_number_of_processors()
{
#ifdef _WIN32
SYSTEM_INFO info;
GetSystemInfo(&info);
return (size_t)info.dwNumberOfProcessors;
#else
return (size_t)sysconf(_SC_NPROCESSORS_ONLN);
#endif
}
matrix_t* matrix_t_multiply(matrix_t* matrix1, matrix_t* matrix2)
{
matrix_t* result;
size_t x;
size_t y;
size_t i;
double sum;
if (!matrix1 || !matrix2)
{
return NULL;
}
if (!matrix1->m_data || !matrix2->m_data)
{
return NULL;
}
if (matrix1->m_cols != matrix2->m_rows)
{
return NULL;
}
result = malloc(sizeof(*result));
matrix_t_init(result, matrix1->m_rows, matrix2->m_cols);
for (y = 0; y != matrix1->m_rows; ++y)
{
for (x = 0; x != matrix2->m_cols; ++x)
{
sum = 0.0;
for (i = 0; i != matrix1->m_cols; ++i)
{
sum += matrix_t_get(matrix1, i, y) *
matrix_t_get(matrix2, x, i);
}
matrix_t_set(result, x, y, sum);
}
}
return result;
}
static const size_t MINIMUM_THREAD_LOAD = 1; /*10 * 1000;*/
typedef struct thread_info {
matrix_t* left_matrix;
matrix_t* right_matrix;
matrix_t* result_matrix;
size_t start_row;
size_t rows;
} thread_info;
#ifdef _WIN32
DWORD WINAPI ThreadProc(LPVOID arg)
#else
static void* thread_func(void* arg)
#endif
{
size_t i;
size_t x;
size_t y;
double sum;
thread_info* info = (thread_info*) arg;
for (y = info->start_row; y < info->start_row + info->rows; ++y)
{
for (x = 0; x < info->right_matrix->m_cols; ++x)
{
sum = 0.0;
for (i = 0; i < info->left_matrix->m_cols; ++i)
{
sum += matrix_t_get(info->left_matrix, i, y) *
matrix_t_get(info->right_matrix, x, i);
}
matrix_t_set(info->result_matrix, x, y, sum);
}
}
return NULL;
}
matrix_t* matrix_t_multiply_parallel(matrix_t* left_matrix,
matrix_t* right_matrix)
{
size_t i;
size_t rows_reserved;
size_t work_load;
size_t num_threads;
size_t basic_rows_per_thread;
thread_info* thread_info_structs;
matrix_t* result_matrix;
work_load = left_matrix->m_rows *
right_matrix->m_cols *
right_matrix->m_rows;
num_threads = get_number_of_processors();
num_threads = min_size_t(num_threads, work_load / MINIMUM_THREAD_LOAD);
num_threads = min_size_t(num_threads, left_matrix->m_rows);
num_threads = max_size_t(num_threads, 1);
if (num_threads == 1)
{
return matrix_t_multiply(left_matrix, right_matrix);
}
result_matrix = matrix_t_alloc(left_matrix->m_rows, right_matrix->m_cols);
if (!result_matrix)
{
return NULL;
}
basic_rows_per_thread = left_matrix->m_rows / num_threads;
thread_info_structs = calloc(num_threads, sizeof(thread_info));
if (!thread_info_structs)
{
matrix_t_free(result_matrix);
return NULL;
}
for (i = 0, rows_reserved = 0;
i != num_threads;
i++, rows_reserved += basic_rows_per_thread)
{
thread_info_structs[i].left_matrix = left_matrix;
thread_info_structs[i].right_matrix = right_matrix;
thread_info_structs[i].result_matrix = result_matrix;
thread_info_structs[i].rows = basic_rows_per_thread;
thread_info_structs[i].start_row = rows_reserved;
}
/* Last thread function will be run in current thread: */
thread_info_structs[num_threads - 1].rows +=
left_matrix->m_rows % basic_rows_per_thread;
#ifdef _WIN32
HANDLE* threads = calloc(num_threads, sizeof(HANDLE));
#else
pthread_t* threads = calloc(num_threads, sizeof(pthread_t));
#endif
for (i = 0; i < num_threads - 1; ++i)
{
#ifdef _WIN32
threads[i] = CreateThread(NULL,
1000000,
ThreadProc,
(void*) &thread_info_structs[i],
0,
NULL);
#else
pthread_create(&threads[i],
NULL,
thread_func,
(void*)&thread_info_structs[i]);
#endif
}
#ifdef _WIN32
ThreadProc((void*) &thread_info_structs[num_threads - 1]);
#else
thread_func((void*)&thread_info_structs[num_threads - 1]);
#endif
#ifdef _WIN32
WaitForMultipleObjects(num_threads - 1, threads, TRUE, INFINITE);
#else
for (i = 0; i < num_threads - 1; ++i)
{
pthread_join(threads[i], NULL);
}
#endif
return result_matrix;
}
void matrix_t_print(matrix_t* matrix)
{
for (size_t y = 0; y < matrix->m_rows; ++y)
{
for (size_t x = 0; x < matrix->m_cols; ++x)
{
printf("%f ", matrix_t_get(matrix, x, y));
}
puts("");
}
}
main.c
#include "matrix.h"
#include "matrix_algorithm.h"
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <sys/time.h>
#include <unistd.h>
#else
#include <windows.h>
#endif
static matrix_t* create_random_matrix(const size_t rows, const size_t cols)
{
size_t x;
size_t y;
matrix_t* m = matrix_t_alloc(rows, cols);
if (!m)
{
return NULL;
}
for (x = 0; x < cols; ++x)
{
for (y = 0; y < rows; ++y)
{
matrix_t_set(m, x, y, ((double)rand()) / RAND_MAX);
}
}
return m;
}
static size_t get_milliseconds()
{
#ifdef _WIN32
return (size_t) GetTickCount64();
#else
struct timeval time;
gettimeofday(&time, NULL);
return time.tv_sec * 1000 + time.tv_usec / 1000;
#endif
}
static int matrix_equals(const matrix_t const* a, const matrix_t const* b)
{
size_t x;
size_t y;
if (a->m_cols != b->m_cols || a->m_rows != b->m_rows)
{
return 0;
}
for (y = 0; y < a->m_rows; ++y)
{
for (x = 0; x < a->m_cols; ++x)
{
if (matrix_t_get(a, x, y) != matrix_t_get(b, x, y))
{
return 0;
}
}
}
return 1;
}
int main() {
size_t start_time;
size_t end_time;
matrix_t* a;
matrix_t* b;
matrix_t* ab1;
matrix_t* ab2;
srand((unsigned int)time(NULL));
a = create_random_matrix(500, 500);
b = matrix_t_copy(a);
start_time = get_milliseconds();
ab1 = matrix_t_multiply(a, b);
end_time = get_milliseconds();
printf("Single-threaded multiplication in %zu milliseconds.\n",
end_time - start_time);
start_time = get_milliseconds();
ab2 = matrix_t_multiply_parallel(a, b);
end_time = get_milliseconds();
printf("%zu-threaded multiplication in %zu milliseconds.\n",
get_number_of_processors(),
end_time - start_time);
printf("Algorithms agree: %d\n", matrix_equals(ab1, ab2));
matrix_t_free(a);
matrix_t_free(b);
matrix_t_free(ab1);
matrix_t_free(ab2);
#ifdef _WIN32
Sleep(5000);
#endif
return 0;
}
The above compiles in Visual C++ 2017 and Xcode 8. Please criticize my code.