Reputation: 1810
I am currently trying to multiply two matrices using a specific number of threads.
I have recently published a post related to the same task (old approach) but now I have changed my strategy to solve this task.
I am not using a thread pool anymore. Instead, I am managing the threads by myself.
This is my current solution:
class Matrix
{
// Stores a random generator
Random rnd = new Random();
int[,] map = new int[16, 16];
// Stores the cell which have to be processed
static List<Cell> TaskList = new List<Cell>();
// Stores the threads used for processing
static List<Thread> Threads = new List<Thread>();
// Stores the result matrix
static Matrix c = new Matrix();
// Fill a matrix with an given value
public void fillMatrixWithValue(int val)
{
for (int i = 0; i < map.GetLength(0); i++)
{
for (int j = 0; j < map.GetLength(1); j++)
{
map[i, j] = val;
}
}
}
// Fill a matrix with random values
public void fillMatrixWithRandomValues(int range = 10)
{
for (int i = 0; i < map.GetLength(0); i++)
{
for (int j = 0; j < map.GetLength(1); j++)
{
map[i, j] = getRandomNumber(range);
}
}
}
// Return a random number for random matrix generation
int getRandomNumber(int range)
{
return rnd.Next(1, range);
}
// Print a matrix to console
public void printMatrix()
{
for (int i = 0; i < map.GetLength(0); i++)
{
for (int j = 0; j < map.GetLength(1); j++)
{
Console.Write(map[i, j] + " ");
}
Console.WriteLine();
}
Console.WriteLine();
}
// Calculate the result matrix sequential
public static Matrix MultiplyMatricesSequential(Matrix a, Matrix b)
{
Matrix c = new Matrix();
for (int row = 0; row < a.map.GetLength(0); row++)
{
for (int col = 0; col < a.map.GetLength(1); col++)
{
for (int i = 0; i < a.map.GetLength(0); i++)
{
c.map[row, col] += a.map[row, i] * b.map[i, col];
}
}
}
return c;
}
// Calculate the result matrix parallel via threads
public static Matrix MultiplyMatricesAsynchronous(Matrix a, Matrix b, int amountOfThreads)
{
// Stores the row values needed for calculation of the result cell value
int[] row = new int[a.map.GetLength(0)];
// Stores the col values needed for calculation of the result cell value
int[] col = new int[a.map.GetLength(1)];
// Store the position indizes of the result cell
int x = 0, y = 0;
// Calculate and store the cell information used for calculation of the result value
for (int i = 0; i < a.map.GetLength(0); i++)
{
for (int j = 0; j < a.map.GetLength(1); j++)
{
for (int k = 0; k < a.map.GetLength(0); k++)
{
row[k] = a.map[i, k];
col[k] = b.map[k, j];
x = i;
y = j;
}
TaskList.Add(new Cell(row, col, x, y));
}
}
// Get the intial amount of threads (created by OS)
int amountOfInitialThreads = Process.GetCurrentProcess().Threads.Count;
// Run till all cells have been processed
do
{
// Only create a new thread if thread limit (user input) has not been reached yet
if (Process.GetCurrentProcess().Threads.Count < (amountOfInitialThreads + amountOfThreads))
{
Thread temp = new Thread(new ThreadStart(calculateCell));
Threads.Add(temp);
temp.Start();
}
foreach (Thread t in Threads)
{
t.Join();
}
} while (TaskList.Count > 0);
return c;
}
// Calculate and set the result value in the result matrix
static void calculateCell()
{
Cell cell = null;
if (TaskList.Count != 0)
{
// Lock the list so that threads do not take the same cell for processing
lock (TaskList)
{
cell = TaskList[TaskList.Count - 1];
TaskList.RemoveAt(TaskList.Count - 1);
}
int temp = 0;
// Calculate and set the result cell value
for (int i = 0; i < cell.row.Length; i++)
{
temp = i;
c.map[cell.x, cell.y] += cell.row[temp] * cell.col[temp];
}
}
}
}
}
I have implemented a cell class which stores the result matrix value position and the row and column values from the base matrices needed for the calculation of the result value.
The problem now is that each cell of the result matrix is filled with the same value.
What I do not understand is that each thread gets the right x and y values but the wrong row and col values (each thread takes the same row and col values). It seems to me that some values are somehow shared between the threads and some are not.
I have done a lot of debugging yet but I cannot figure out what I am doing wrong.
Is anyone of you able to do so?
Upvotes: 0
Views: 783
Reputation: 2354
The problem is here
// Stores the row values needed for calculation of the result cell value
int[] row = new int[a.map.GetLength(0)];
// Stores the col values needed for calculation of the result cell value
int[] col = new int[a.map.GetLength(1)];
// Store the position indizes of the result cell
int x = 0, y = 0;
// Calculate and store the cell information used for calculation of the result value
for (int i = 0; i < a.map.GetLength(0); i++)
{
for (int j = 0; j < a.map.GetLength(1); j++)
{
for (int k = 0; k < a.map.GetLength(0); k++)
{
row[k] = a.map[i, k];
col[k] = b.map[k, j];
Note you are using the same row/col array for all cells as they are defined outside the loops.
You need to move array declarations inside "j" loop to get a new set of arrays for every cell
Upvotes: 1