//This function first creates the designated amount of matrices with randomly generated numbers in them and then multiplies the matrices with one another using threads to multiply different sections of the matrix simultaneously private RandomMatrix CreateAndMultiplayMatrices(int poolSize, int numOfMatrices, int matrixDim) { CustomThreadPool threadPool = new CustomThreadPool(); //Creates a thread pool List <RandomMatrix> matrices = new List <RandomMatrix>(); //Creates a vector of matrices MatrixConcurrentQueue multiMatrixQueue = new MatrixConcurrentQueue(); //A custom Queue class that holds the matrices and the amount of multiplications that have been completed threadPool.SetThreadPoolSize(poolSize); //Set the thread pool's pool size (amount of threads) //Initializes the matrix array with matrices for (int i = 0; i < numOfMatrices; i++) { //Initializes the current matrix RandomMatrix currMatrix = new RandomMatrix(matrixDim); matrices.Add(currMatrix); for (int j = 0; j < poolSize; j++) { //Splits the matrix into segments so each thread will randomize values for a different segment of the matrix int threadRandPart = j; WaitCallback task = () => MatrixUtils.ThreadingCreateRandomMatrix(currMatrix, poolSize, threadRandPart, matrixDim); //Saves the task into a callback threadPool.QueueTask(task); //Queues the task so the thread pool will allocate a thread to run it } } threadPool.DoneWorking.WaitOne(); //Waits for all threads to finish before continuing //Enqueues all the matrices into a Concurrent Queue so it can run constantly until all the matrices have been multiplied and only the final result matrix remains foreach (RandomMatrix mat in matrices) { multiMatrixQueue.m_MatrixQueue.Enqueue(mat); } //Runs across the queue, sending 2 matrices at a time to the multiplication method while (multiMatrixQueue.numOfOperations < numOfMatrices - 1) { RandomMatrix matA = null; //matrix that will hold the 1st matrix RandomMatrix matB = null; //matrix that will hold the 2nd matrix if (multiMatrixQueue.m_MatrixQueue.Count > 1) //checks if theres more than one matrix in the queue, so it won't attempt to multiply a null matrix { multiMatrixQueue.m_MatrixQueue.TryDequeue(out matA); //Tries to dequeues the 1st matrix into matA multiMatrixQueue.m_MatrixQueue.TryDequeue(out matB); ////Tries to dequeues the 2nd matrix into matA } if (matA != null && matB != null) { RandomMatrix resMatrix = new RandomMatrix(matrixDim); //Creates a result matrix to hold the multiplication result multiMatrixQueue.m_MatrixQueue.Enqueue(resMatrix); //Insers the result matrix into the queue int matrixPartsLeft = poolSize; //Amount of parts the matrix multiplication will be split into //Divides the matrix multiplication work, so each thread calculates the matrix multiplication in different parts of the matrices for (int i = 0; i < poolSize; i++) { int threadMultiPart = i; //saves the index in order to avoid it being different when the task is executed WaitCallback task = () => MatrixUtils.ThreadingMultiplyMatrices(resMatrix, matA, matB, multiMatrixQueue, ref matrixPartsLeft, poolSize, threadMultiPart, matrixDim); threadPool.QueueTask(task); } // threadPool.DoneWorking.WaitOne(); } } threadPool.DoneWorking.WaitOne(); //Waits for all threads to finish before continuing RandomMatrix finalMatrix; multiMatrixQueue.m_MatrixQueue.TryDequeue(out finalMatrix); //Dequeues the final result matrix and returns it. return(finalMatrix); }
public static void ThreadingMultiplyMatrices(RandomMatrix result, RandomMatrix matA, RandomMatrix matB, MatrixConcurrentQueue matrixQueue, ref int matrixPartsLeft, int numOfThreads, int threadPart, int matrixDim) { // Calculates the workload for the current thread int numOfElements = (matrixDim * matrixDim); //Holds the number of elements in the matrix int numOfOperations = numOfElements / numOfThreads; //Holds the number of operations (iterations) that will be done int restOfOperations = numOfElements % numOfThreads; //Holds the extra number of operations the first thread will have to do int startPosition, endPosition; //Holds the starting and ending indexes if (threadPart == 0) { //First thread does the extra work left by the other threads (the remainder) startPosition = numOfOperations * threadPart; endPosition = (numOfOperations * (threadPart + 1)) + restOfOperations; } else { startPosition = numOfOperations * threadPart + restOfOperations; endPosition = (numOfOperations * (threadPart + 1)) + restOfOperations; } //Randomizes the segment in the matrix the current thread is incharge of, in this case a segment of cells in the result matrix that will be calculated from multiplying Matrix A and Matrix B for (int pos = startPosition; pos < endPosition; ++pos) { int row = pos % matrixDim; //Calcuates the current row int col = pos / matrixDim; //Calculates the current column int resCell = 0; //Multiplies the current row in Matrix A with the current column in matrix B and saves the result in the appropriate cell in the result matrix for (int i = 0; i < matrixDim; ++i) { int cellA = matA.Matrix[row, i]; int cellB = matB.Matrix[i, col]; resCell += cellA * cellB; } result.Matrix[row, col] = resCell; } //The current segment in the result matrix has been completed so the matrixPartsLeft counter gets decremented Interlocked.Decrement(ref matrixPartsLeft); //If the matrixPartsLeft counter reaches 0, we have finished calculating the multiplication of all the segments of the result matrix if (matrixPartsLeft == 0) { //Since the result matrix is complete we increment the number of completed matrix multiplication opreations in the matrix multiplication queue Interlocked.Increment(ref matrixQueue.numOfOperations); } }