4

私は一晩中これを調査してきましたが、解決策が見つからなかったので、誰かが私を助けることができれば、本当に感謝しています! 私はおそらく、非常に明白な何かを見逃しています。これは、スレッドを使用して 2 つの行列を乗算する前の割り当てを行っている同期を理解するための割り当てです。前の割り当てでは、各スレッドが行を乗算したため、行と同じ数のスレッドがありました。

この割り当てでは、5 つのスレッドのみを使用することになっています。すべてのスレッドは 1 つの行/列から開始し、スレッドが完了すると、同期を使用して次に使用可能な行/列を選択する必要があるため、2 つのスレッドが最終的に同じ列。

この質問は私を正しい方向に導くのに役立ちましたが、これまでのところプログラムを次のいずれかにしか取得していないため、実装で何か間違ったことをしているに違いありません。

  1. 最初の 5 行のみを実行します。5 つのスレッドが 1 回実行され、それぞれが行または
  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;

}
}

そして、これは実行可能な私のクラスです:

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

繰り返しますが、何か助けていただければ幸いです。本当にありがとう。

4

4 に答える 4

3
  1. リソースで同期していません。(静的コンテキストまたはコンストラクターで) ロック オブジェクトを共有する必要があります。
  2. 同期的に動作させない場合でも、プログラムの何を同期する必要があるかを実際に理解することはできません....スレッドを開始し、スレッドが停止するのを直接待ちます。最初にそれらをすべて開始してから、別のループですべてのスレッドで結合を呼び出す必要があると思います。

また、スレッドが個別にどのように機能するかはよくわかりません。それらはすべて、製品マトリックス全体を機能させると思います。同期してアクセスする、既に処理された行を識別するために使用される変数を共有する必要があります。

私はあなたのコードを修正することができますが、それはスレッドの同時実行性を理解するための作業であるため、ご自身で行っていただければ幸いです。

編集:同期の説明:
同期はオブジェクトをロックとして受け取り、1つのスレッドのみがそのモニターを保持できます。ロックのモニターがある場合、スレッドはブロックを処理できますが、そうでない場合は、モニターを取得するまで待機する必要があります。
あなたの場合、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;
        }
    }
}

そして処理タスク

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;

    }
}
于 2012-11-21T14:41:09.647 に答える
1

問題に取り組むには、「作業単位」を構成するものを定義する必要があります。この「作業単位」(またはタスク) は、各スレッドが実行するものです。それが定義された後、この作業単位がその作業を行うために必要なものについて推論できます。

行列乗算の場合、自然な作業単位は、結果の行列の各セルです。したがって、行列 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
   }
}

ここで、セルと行列 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結果マトリックスを更新するために同期したことに注意してください。定義上、1 つの同じセルに同時にアクセスする可能性はありませんが (すべてのスレッドが異なるセルで動作するため)、オブジェクトを明示的に同期して、結果が他のスレッドに「安全に公開」されるようにする必要があります。これは宣言によっても実行できresult volatileますが、まだその根拠をカバーしているかどうかはわかりません。

これが、並行性の問題に対処する方法を理解するのに役立つことを願っています。

于 2012-11-21T18:43:56.480 に答える
0

あなたは前の質問の答えを本当に誤解していました。rowToWorkスレッド間で共有する必要があります。また、スレッドはおそらく構築時にメソッドを呼び出して、初期値を取得する必要があります。クリティカル セクションは、特定のスレッドへの次の行の帰属であることを理解する必要があります。

于 2012-11-21T15:22:52.353 に答える
0

同期プリミティブのすべてのスペクトルを使用します: セマフォ、ロック、同期。物事を学ぶために、同期のみから始めることをお勧めします。実際に必要なのは、処理する次の行/列がある場合はそれを示すリソースです。すべてのスレッドは、同期ブロックを使用してアクセスし、次の行/列を読み取り、行/列を次のセルに移動し、ブロックを終了し、取得した行/列を処理します。

マトリックスの終わりに達した場合、作業スレッドは単純に終了します。メイン スレッドは、すべてのワーカー スレッドが Thread.join() で終了するのを待ちます。

于 2012-11-21T14:44:23.520 に答える