0

It takes m iterations to transform the array according to the rule: a[i]=(a[i-1]+a[i+1])/2 Also, according to the assignment, I must use Thread and Phaser. Using of Thread and Phaser is mandatory, and there is no way I can refuse to use them.

For transforming I use this code:

package lab3;
 
import java.util.concurrent.Phaser;
 
public class Program {
    public static void main(String[] args) 
    {
        int n = 100;
        int m = 100;
        int [] arr;
        arr = new int [n];
        int [] arr2;
        arr2 = new int [n];
        for (int i = 0; i<n; i++)
        {
            int r = (int)(Math.random()*50);
            arr [i] = r;
            arr2 [i] = r;
            System.out.print(arr[i]+" ");
        }
        int [] arr3 = arr2.clone();
        System.out.println(" ");
        for (int p = 0; p<m; p++)
            for (int i = 1; i<n-1; i++)
            {
                arr [i] = (arr [i-1]+arr [i+1])/2;
            }
        
        for (int i = 0; i<n; i++)
        {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
        Sum.arr = arr2;
        Sum.m=m;
        Phaser p = new Phaser();
            for (int i = 1; i<n-1; i++)
            {
                var x = new Sum (p, i);
                x.start();
            }
        for (int i = 0; i<n; i++)
        {
            System.out.print(Sum.arr[i]+" ");
        }
        System.out.println();
        for (int i = 0; i<n; i++)
        {
            if (arr[i]!=Sum.arr[i])
                System.out.println("Error! Value is incorrect at position: "+i+". Original val is: "+arr[i]+" Thead val is: "+Sum.arr[i]+" Before transform is: " +arr3[i]);
        }
    }
}
 
class Sum extends Thread 
{
    static int [] arr;
    static int m;
    Phaser ph;
    int i;
    
    public Sum(Phaser p, int i)
    {
        this.ph = p;
        this.i = i;
    }
    
    public static synchronized void trans (int i)
    {
        arr [i]= (arr [i-1]+arr [i+1])/2;
    }
    
    @Override
    public void run ()
    {
        ph.register();
        for (int j = 0; j<m; j++)
        {
            trans(i);
            ph.arriveAndAwaitAdvance();
        }
        ph.arriveAndDeregister();
    }
}

However, the results of serial and parallel algorithms are not the same. Please tell me what am I doing wrong?

  • Seems to me like all threads are mutating the same array, but not necessarily in the same order as the sequential code. So some threads will probably read old values in `arr[i - 1]` and `arr[i + 1]`, while others will read new values. – marstran Nov 16 '22 at 14:39
  • @marstran and how can I fix it? – Mikhail Kondaurov Nov 16 '22 at 14:41
  • I would separate the array you read from and write to into 2 arrays, and do: `writeArr[i]=(readArr[i-1]+readArr[i+1])/2`. But I'm not sure that will yield the correct answer considering your sequential code also seem to read both old and newly written values. – marstran Nov 16 '22 at 14:41
  • @marstran unfortunately, it doesn't work :( – Mikhail Kondaurov Nov 16 '22 at 15:38
  • Is it intended that your sequential code uses values that just got updated by the iteration? For example, let's say you have `{ 1, 2, 3 }` and want to perform `a[i] = a[i - 1] + a[i + 1]`, where `a[x] = 0` if x is out of bounds of the array. Basically saying that each item should be the sum of its neighbours. Then I would expect the result `{ 2, 4, 2 }`. But if you iterate over the array and mutate it at the same time, you would get this: `after i=0 -> { 2, 2, 3 }`, `after i=1 -> { 2, 5, 3 }`, `after i=2 -> { 2, 5, 5 }`. I think you have the same issue with your code. – marstran Nov 16 '22 at 16:11
  • @marstran yes, I should use updated values – Mikhail Kondaurov Nov 16 '22 at 16:48

2 Answers2

0

I can see 2 problems:

  1. you don't wait for the Sum threads to finish before checking the results:
        Phaser p = new Phaser();
        for (int i = 1; i<n-1; i++)
        {
            var x = new Sum (p, i);
            x.start();
        }
        // YOU SHOULD WAIT HERE UNTIL ALL THE STARTED Sum THREADS ARE FINISHED
        for (int i = 0; i<n; i++)
        {
            System.out.print(Sum.arr[i]+" ");
        }
        System.out.println();
    
  2. in Sum threads you don't wait for arr[i-1] and arr[i+1] to get computed before computing arr[i].
    Don't forget that Sum.run() are executed in parallel (because they are executed in different threads), and when some thread computes a[i], then there are no guarantees that the other threads have just computed the right iterations of a[i-1] and a[i+1].
0

It seems like the question has transformed into:

how can I synchronize Sum.run()? how can I run it serially?

The answer is that you should probably use Phaser for synchronization because:

according to the assignment, I must use Thread and Phaser

You can learn how Phaser works here:

  1. official Phaser javadocs
  2. Guide to the Java Phaser on Baeldung

If the above resources aren't clear to you, then I can recommend Java Concurrency in Practice - this book explains concurrency in Java in great details and is ideal for novices in the topic.


Also I would recommend you to check one more time if you understood your assignment correctly.

Because right now (the way you explained it) your assignment looks weird:

  • one one hand the algorithm you described cannot be split into parallel subtasks: in order to compute a[i+1] we need a[i] from the same iteration.
  • on the other hand you should use threads, whose sole purpose is to perform work in parallel

To use threads with an algorithm that can only work sequentially is weird because this way you get only negatives: the program becomes more complicated and its performance decreases.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 20 '22 at 14:20