使用用户设置的线程数的矩阵乘法

时间:2016-04-23 12:29:35

标签: c# .net multithreading matrix

我目前正在尝试使用特定数量的线程将两个矩阵相乘。

我最近发布了一篇与同一任务(old approach)相关的帖子,但现在我已经改变了解决此任务的策略。

我不再使用线程池了。相反,我自己管理线程。

这是我目前的解决方案:

    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];
                }
            }
        }
    }
}

我已经实现了一个单元类,它存储结果矩阵值的位置以及计算结果值所需的基本矩阵的行和列值。

现在的问题是结果矩阵的每个单元格都填充了相同的值。

我不明白的是每个线程获得正确的x和y值,但是错误的行和col值(每个线程采用相同的行和col值)。在我看来,某些值在线程之间以某种方式共享,而有些则不是。

我已经做了很多调试,但我无法弄清楚我做错了什么。

你们中有人能够这样做吗?

1 个答案:

答案 0 :(得分:1)

问题出在这里

         // 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];

请注意,对于所有单元格使用相同的row / col数组,因为它们是在循环外部定义的。

您需要在“j”循环内移动数组声明,以便为每个单元格获取一组新的数组