簡體   English   中英

用於乘法矩陣的同步線程

[英]Synchronized threads for multiplying matrices

我一直在研究這個問題並且沒有找到解決方案,所以如果有人能幫助我,我真的很感激! 我可能錯過了一些非常明顯的東西。 這是一個理解同步的賦值,我們在前面的賦值中使用線程來乘以2個矩陣。 在前面的賦值中,每個線程乘以一行,因此線程數與行數一樣多。

在這個賦值中,我們只應該使用5個線程 - 所有線程都應該以一行/一列開始,一旦線程完成,它應該使用同步選擇下一個可用的行/列,所以現在兩個線程將最終執行同一欄。

這個問題幫助我找到了正確的方向,但我必須對實現做錯了,因為到目前為止我只得到了以下任一項目:

  1. 只執行前5行 - 5個線程執行一次,每個線程計算一行或
  2. 我添加了一個循環(現在在我的代碼中注釋掉了),所以線程會繼續執行,但是當我這樣做時,只有第一個線程做任何工作。

這是我的主要和幾個輔助方法的類:

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;

public class MatrixMult {

public static void main(String[] args){
    int[][] matrixA;
    int[][] matrixB;
    int colA = 0;
    int rowA = 0;
    int colB = 0;
    int rowB = 0;
    Scanner userInput = new Scanner( System.in );
    System.out.println("Please enter the dimensions of matrix A");

    do{
        System.out.print("column for matrix A: ");
        colA = userInput.nextInt();
        System.out.println();
    } while(!validDimension(colA));

    rowB = colA;

    do{
        System.out.print("row for matrix A: ");
        rowA = userInput.nextInt();
        System.out.println();
    } while(!validDimension(rowA));

    matrixA = new int[rowA][colA];

    System.out.println("Please enter the dimensions of matrix B:");
    do{
        System.out.print("column for matrix B: ");
        colB = userInput.nextInt();
        System.out.println();
    } while(!validDimension(colB));

    matrixB = new int[rowB][colB];


    fillMatrix(matrixA);
    fillMatrix(matrixB);

    System.out.println("Would you like to print out matrix A and B? (y/n)");
    String userResponse = userInput.next();
    if(userResponse.equalsIgnoreCase("y")){
        System.out.println("Matrix A:");
        printBackMatrix(matrixA);
        System.out.println();
        System.out.println("Matrix B:");
        printBackMatrix(matrixB);
        System.out.println();
    }


    int[][] matrixProduct3 = multMatrixWithThreadsSync(matrixA, matrixB);

    String fileName = "C:/matrix.txt";
    System.out.println("Matrix product is being written to "+fileName);
    try {
        printMatrixToFile(matrixProduct3, fileName);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private static int[][] multMatrixWithThreadsSync(int[][] matrixA, int[][] matrixB) {

    int[][] matrixProduct = new int[matrixA.length][matrixB[0].length];
    int[] matrixProductColumn = new int[matrixA.length];

    Runnable task = new MultMatrixByRow(matrixA, matrixB, matrixProduct);

    for(int i=0; i<5; i++){

        Thread worker = new Thread(task);
        worker.start();
//          System.out.println(worker.getName());
        try {
            worker.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    return matrixProduct;
}

private static void printMatrixToFile(int[][] matrix, String fileName) throws IOException{
    PrintWriter userOutput = new PrintWriter(new FileWriter(fileName));
    for(int i=0; i<matrix.length; i++){
        for(int j=0; j<matrix[0].length; j++){
            userOutput.print(matrix[i][j]+" ");
        }
        userOutput.println();
    }
    userOutput.close();

}

private static void printBackMatrix(int[][] matrix) {
    for(int i=0; i<matrix.length; i++){
        for(int j=0; j<matrix[0].length; j++){
            System.out.print(matrix[i][j]+" ");
        }
        System.out.println();
    }
}

private static void fillMatrix(int[][] matrix) {
    Random rand = new Random();

    for(int i=0; i<matrix.length; i++){
        for(int j=0; j<matrix[0].length; j++){
            matrix[i][j] = rand.nextInt(100) + 1;
        }
    }

}

public static boolean validDimension(int dim){
    if (dim <= 0 || dim >1000){
        System.err.println("Dimension value entered is not valid");
        return false;
    }
    return true;

}
}

這是我的runnable類:

public class MultMatrixByRow implements Runnable {
private int i;
private int[][] matrixA;
private int[][] matrixB;
private int[][] matrixProduct;

public MultMatrixByRow(int[][] A, int[][] B, int[][] C) {
    this.matrixA = A;
    this.matrixB = B;
    this.matrixProduct = C;
}

@Override   
public void run(){
//      while(i < matrixProduct.length){
        int rowToWork = 0;
        synchronized (this){
 //             System.out.println("i is "+i);
            if ( i < matrixProduct.length){
                rowToWork = i;
                i++;
            }
            else{
                return;
            }
        }
        for(int j = 0; j < matrixB[0].length; j++){
            for(int k=0; k < matrixA[0].length; k++){
                matrixProduct[rowToWork][j] += matrixA[rowToWork][k]*matrixB[k][j];
            }
        }
//      }
        }
    }

再次 - 任何幫助真的很感激! 非常感謝。

  1. 您沒有在資源上進行同步,您需要共享一個鎖對象(在靜態上下文中或通過構造函數)
  2. 當你甚至不讓它們同步工作時,我真的無法弄清楚你的程序中應該同步什么....你啟動一個線程並直接等待他停止。 我認為你必須首先啟動它們然后在另一個循環中調用每個線程上的連接。

另外,我不太確定你的Threads應該分別運作,我認為它們都可以解決整個產品矩陣。 您需要共享一個用於標識已處理的行的變量,您可以訪問這些行進行同步。

我可以修復你的代碼,但我很感激你自己做這項工作,因為這是一個理解線程並發的任務。

編輯:同步說明:
Synchronized將一個對象作為一個鎖,只有一個線程可以為它保存監視器。 當有監視器用於鎖定時,線程可以處理該塊,如果沒有,他必須等待獲取監視器。
在您的情況下,您可以使用private static final Object lock = new Object(); 作為鎖定,您將同步。

編輯2:我完全構建了你的代碼
我沒有為完成你所有的工作而自豪,但沒關系,這就是它。

package anything.synchronize_stackoverflow_post;

/**
 * @date 21.11.2012
 * @author Thomas Jahoda
 */
public class ConcurrentMatrixMultiplyingTask implements Runnable {

    private int[][] matrixA;
    private int[][] matrixB;
    private int[][] matrixProduct;
    //
    private final ConcurrencyContext context;

    public ConcurrentMatrixMultiplyingTask(ConcurrencyContext context, int[][] A, int[][] B, int[][] C) {
        if (context == null) {
            throw new IllegalArgumentException("context can not be null");
        }
        this.context = context;
        this.matrixA = A;
        this.matrixB = B;
        this.matrixProduct = C;
    }

    @Override
    public void run() {
        while (true) {
            int row;
            synchronized (context) {
                if (context.isFullyProcessed()) {
                    break;
                }
                row = context.nextRowNum();
            }
            System.out.println(Thread.currentThread().getName() + " is going to process row " + row);
            // i'm not really sure if this matrix algorithm here is right, idk..
            for (int j = 0; j < matrixB[0].length; j++) {
                for (int k = 0; k < matrixA[0].length; k++) {
                    matrixProduct[row][j] += matrixA[row][k] * matrixB[k][j];
                }
            }
        }
    }

    public static class ConcurrencyContext {

        private final int rowCount;
        private int nextRow = 0;

        public ConcurrencyContext(int rowCount) {
            this.rowCount = rowCount;
        }

        public synchronized int nextRowNum() {
            if (isFullyProcessed()) {
                throw new IllegalStateException("Already fully processed");
            }
            return nextRow++;
        }

        public synchronized boolean isFullyProcessed() {
            return nextRow == rowCount;
        }
    }
}

和ProcessingTask

package anything.synchronize_stackoverflow_post;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @date 21.11.2012
 * @author Thomas Jahoda
 */
public class MatrixMulti {

    public static void main(String[] args) {
        int[][] matrixA;
        int[][] matrixB;
        int colA = 0;
        int rowA = 0;
        int colB = 0;
        int rowB = 0;
        Scanner userInput = new Scanner(System.in);
        System.out.println("Please enter the dimensions of matrix A");

        do {
            System.out.print("column for matrix A: ");
            colA = userInput.nextInt();
            System.out.println();
        } while (!validDimension(colA));

        rowB = colA;

        do {
            System.out.print("row for matrix A: ");
            rowA = userInput.nextInt();
            System.out.println();
        } while (!validDimension(rowA));

        matrixA = new int[rowA][colA];

        System.out.println("Please enter the dimensions of matrix B:");
        do {
            System.out.print("column for matrix B: ");
            colB = userInput.nextInt();
            System.out.println();
        } while (!validDimension(colB));

        matrixB = new int[rowB][colB];


        fillMatrix(matrixA);
        fillMatrix(matrixB);

        System.out.println("Would you like to print out matrix A and B? (y/n)");
        String userResponse = userInput.next();
        if (userResponse.equalsIgnoreCase("y")) {
            System.out.println("Matrix A:");
            printBackMatrix(matrixA);
            System.out.println();
            System.out.println("Matrix B:");
            printBackMatrix(matrixB);
            System.out.println();
        }


        int[][] matrixProduct3 = multMatrixWithThreadsSync(matrixA, matrixB);

        String fileName = "test.txt";
        System.out.println("Matrix product is being written to " + fileName);
        try {
            printMatrixToFile(matrixProduct3, fileName);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private static int[][] multMatrixWithThreadsSync(int[][] matrixA, int[][] matrixB) {

        int[][] matrixProduct = new int[matrixA.length][matrixB[0].length];
        int[] matrixProductColumn = new int[matrixA.length];
        //
        ConcurrentMatrixMultiplyingTask.ConcurrencyContext context = new ConcurrentMatrixMultiplyingTask.ConcurrencyContext(matrixProduct.length);
        //
        Runnable task = new ConcurrentMatrixMultiplyingTask(context, matrixA, matrixB, matrixProduct);
        Thread[] workers = new Thread[5];
        for (int i = 0; i < workers.length; i++) {
            workers[i] = new Thread(task, "Worker-"+i);
        }
        for (int i = 0; i < workers.length; i++) {
            Thread worker = workers[i];
            worker.start();
        }
        for (int i = 0; i < workers.length; i++) {
            Thread worker = workers[i];
            try {
                worker.join();
            } catch (InterruptedException ex) {
                Logger.getLogger(MatrixMulti.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return matrixProduct;
    }

    private static void printMatrixToFile(int[][] matrix, String fileName) throws IOException {
        PrintWriter userOutput = new PrintWriter(new FileWriter(fileName));
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                userOutput.print(matrix[i][j] + " ");
            }
            userOutput.println();
        }
        userOutput.close();

    }

    private static void printBackMatrix(int[][] matrix) {
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }

    private static void fillMatrix(int[][] matrix) {
        Random rand = new Random();

        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                matrix[i][j] = rand.nextInt(100) + 1;
            }
        }

    }

    public static boolean validDimension(int dim) {
        if (dim <= 0 || dim > 1000) {
            System.err.println("Dimension value entered is not valid");
            return false;
        }
        return true;

    }
}

要解決您的問題,您需要定義什么是“工作單位”。 這個“工作單元”(或任務)是每個線程將要執行的。 在定義之后,您可以推斷出這個工作單元需要做什么工作。

在矩陣乘法的情況下,自然工作單元是所得矩陣的每個單元。 因此,給定矩陣A [i,j]和B [j,k],您的計算可以集中在矢量A.row(x)(點)B.column(y)的每個點的乘積(0<=x<i,0<=y<k)

下一步是代表每項任務。 將任務“提供”到線程的理想結構是隊列。 java.util.concurrent.BlockingQueue就是這樣一個例子,同步工作在幕后完成。 鑒於您被要求“手動”推理同步,您可以使用另一個容器,如List(甚至是數組)。 您的結構將包含定義結果矩陣的每個單元格。 可能是這樣的:

class Cell;  // int x, int y, getters, setters, ...
// build the structure that contains the work to be shared
List<Cell> cells = new LinkedList<Cell>();
for (int i=0;i<a.rows;i++) {
   for (int j=0;j<b.columns;j++) {
       cells.add(new Cell(i,j)); // represent the cells of my result matrix
   }
}

現在,您需要一個給定Cell和Matrices A和B的任務,可以計算該單元格的值。 這是您的工作單元,因此在線程的上下文中運行的是什么。 在這里,您還需要決定是否要放置結果。 在java中你可以使用future並在線程的上下文之外組裝你的矩陣,但是為了簡單起見,我將共享一個可以保存結果的數組。 (根據定義,不會有任何碰撞)

class DotProduct implements Runnable {
 int[][] a;
 int[][] b;
 int[][] result; 
 List<Cell> cells;
 public DotProduct(int[][] a, int[][] b, int[][]result, List<Cell> cells) {
 ...
 }
 public void run() {
     while(true) {
         Cell cell = null;
         synchronized(cells) { // here, we ensure exclusive access to the shared mutable structure
             if (cells.isEmpty()) return; // when there're no more cells, we are done.
             Cell cell = cells.get(0); // get the first cell not calculated yet
             cells.remove(cell);  // remove it, so nobody else will work on it
         }
         int x = cell.getX();
         int y = cell.getY();
         z = a.row(x) (dot) b.column(y);
         synchronized (result) {
             result[x][y] = z;
         }
     }
}

現在你差不多完成了。 您仍然需要做的唯一事情是創建線程,使用DotProduct任務“提供它們”並等待它們完成。 請注意,我在result上同步以更新結果矩陣。 雖然根據定義,並不存在並發訪問同一個單元的可能性(因為每個線程都在不同的單元上工作),但您需要通過顯式同步對象來確保結果“安全地”發布到其他線程。 這也可以通過聲明result volatile來完成,但我不確定你是否已經覆蓋了這個基礎。

希望這有助於理解如何處理並發問題。

您使用所有頻譜的同步原語:信號量,鎖定,同步。 最好從同步開始,學習東西。 您實際需要的是一個資源,它指示要處理的下一行/列(如果有)。 所有線程使用synchronized塊訪問它,讀取下一行/列,將行/列移動到下一個單元格,退出塊,然后處理獲得的行/列。

如果滿足矩陣的結束,工作線程就會退出。 主線程等待所有工作線程使用Thread.join()退出。

你真的誤解了上一個問題的答案。 rowToWork需要在線程之間共享。 一個線程應該在構造時調用一個方法來獲取它的初始值。 您需要了解您的關鍵部分是給定線程的下一行的歸屬。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM