Semafory Java

GO
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:12
0

Witam, mam za zadanie (semafory) stworzyć pętle 30 linii, gdzie w każdej ma się pojawić CBACBADDE. Prowadzący zajęcia powiedział, że niewiele mi brakuje do poprawnego zadania, a ja pomimo wielu prób nie potrafię go poprawnie zmodyfikować. Z góry dziękuję za pomoc.

'''
package sample;

import java.util.concurrent.Semaphore;
public final class Controller {
private static final int COUNT = 30;
private static int COUNTER = 0;
private static final int STEP = 9;
private static final Semaphore a = new Semaphore(0, true);
private static final Semaphore b = new Semaphore(0, true);
private static final Semaphore c = new Semaphore(1, true);
private static final Semaphore d = new Semaphore(0, true);
private static final Semaphore e = new Semaphore(0, true);

public static void main(String[] args) {
    new A().start();
    new B().start();
    new C().start();
    new D().start();
    new E().start();
}

private static final class A extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT * 2; i++) {
                a.acquire();
               // b.release();
              //  a.acquire();
                myPrint("A ");
                c.release();
                d.release();
            }
        }
        catch (InterruptedException ex) {
        }
    }
}

private static final class B extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT * 2; i++) {
                b.acquire();
                myPrint("B ");
                a.release();
            }
        }
        catch (InterruptedException ex) {
        }
    }
}

private static final class C extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT * 2; i++) {
                c.acquire();
                myPrint("C ");
                b.release();


            }
        }
        catch (InterruptedException ex) {
        }
    }
}

private static final class D extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT * 2; i++) {
                d.acquire();
                c.release();
                d.acquire();
                myPrint("D ");
                e.release();
            }
        }
        catch (InterruptedException ex) {
        }
    }
}
private static final class E extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT; i++) {
                e.acquire();
                myPrint("E ");
                c.release();
            }
        }
        catch (InterruptedException ex) {
        }
    }
}
private static synchronized void myPrint(String s) {
    COUNTER++;
    System.out.print(s);
    if (COUNTER == STEP) {
        COUNTER = 0;
        System.out.println();
    }
}

}
'''java

edytowany 1x, ostatnio: Gorth
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Postów:1875
1

Jaka jest dokładnie treść zadania? Każdej pozycji w ciągu można przyporządkować osobny semafor tak, aby wszystko zsynchronizować (tablica semaforów).

Można tez wypisywać w pętli „CBACBADDE” ale raczej nie o to chodzi xD podaj treść.


”Engineering is easy. People are hard.” Bill Coughran
edytowany 3x, ostatnio: Charles_Ray
damianem
  • Rejestracja:prawie 8 lat
  • Ostatnio:4 miesiące
  • Postów:205
0

Jest prawie dobrze, ale trochę przekombinowałeś z A i D. Dla A nie powinieneś iterować COUNT * 2 razy, ponieważ za drugim razem przechodzisz do D a nie do C. Otwieranie jednocześnie semafora c i d nie jest dobrym pomysłem:

Kopiuj
                // A
                for (int i = 0; i < COUNT; i++) {
                    a.acquire();
                    myPrint("A ");
                    c.release();
                    a.acquire();
                    myPrint("A ");
                    d.release();
                }

I D się znacznie upraszcza:

Kopiuj
                // D
                for (int i = 0; i < COUNT * 2; i++) {
                    d.acquire();
                    myPrint("D ");
                    myPrint("D ");
                    e.release();
                }
GO
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:12
0
Charles_Ray napisał(a):

Jaka jest dokładnie treść zadania? Każdej pozycji w ciągu można przyporządkować osobny semafor tak, aby wszystko zsynchronizować (tablica semaforów).

Można tez wypisywać w pętli „CBACBADDE” ale raczej nie o to chodzi xD podaj treść.

Stosując semafory zmodyfikuj plik ABCwithSem.java tak, by na standardowym
wyjściu (konsoli) 30 razy pojawiał się napis: CBACBADDE. Tylko jeden wątek wypisuje jedną literę, tj. tylko wątek A wypisuje literę A. W jednej iteracji pętli for(…) można tylko raz wywołać metodę myPrint(…) Pojedyncze wywołanie metody myPrint(…) wypisuje tylko jedną literę

GO
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:12
0
damianem napisał(a):

Jest prawie dobrze, ale trochę przekombinowałeś z A i D. Dla A nie powinieneś iterować COUNT * 2 razy, ponieważ za drugim razem przechodzisz do D a nie do C. Otwieranie jednocześnie semafora c i d nie jest dobrym pomysłem:

Kopiuj
                // A
                for (int i = 0; i < COUNT; i++) {
                    a.acquire();
                    myPrint("A ");
                    c.release();
                    a.acquire();
                    myPrint("A ");
                    d.release();
                }

I D się znacznie upraszcza:

Kopiuj
                // D
                for (int i = 0; i < COUNT * 2; i++) {
                    d.acquire();
                    myPrint("D ");
                    myPrint("D ");
                    e.release();
                }

Dzieki za odpowiedź, ale zapomniałem dodać, że tylko jeden wątek wypisuje jedną literę, tj. tylko wątek A wypisuje literę A. W jednej iteracji pętli for(…) można tylko raz wywołać metodę myPrint(…) Pojedyncze wywołanie metody myPrint(…) wypisuje tylko jedną literę

Charles_Ray
Wrzuć jeszcze kod bez Twoich zmian
GO
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:12
0
Charles_Ray napisał(a):

Jaka jest dokładnie treść zadania? Każdej pozycji w ciągu można przyporządkować osobny semafor tak, aby wszystko zsynchronizować (tablica semaforów).

Można tez wypisywać w pętli „CBACBADDE” ale raczej nie o to chodzi xD podaj treść.

'''java
import java.util.concurrent.Semaphore;

public final class ABCwithSem {
private static final int COUNT = 30;
private static int COUNTER = 0;
private static final int STEP = 3;
private static final Semaphore a = new Semaphore(1, true);
private static final Semaphore b = new Semaphore(0, true);
private static final Semaphore c = new Semaphore(0, true);

public static void main(String[] args) {
    new A().start();
    new B().start();
    new C().start();
}

private static final class A extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT; i++) {
                a.acquire();
                myPrint("A ");
                b.release();
            }
        } catch (InterruptedException ex) {
        }
    }
}

private static final class B extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT; i++) {
                b.acquire();
                myPrint("B ");
                c.release();
            }
        } catch (InterruptedException ex) {
        }
    }
}

private static final class C extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT; i++) {
                c.acquire();
                myPrint("C ");
                a.release();
            }
        } catch (InterruptedException ex) {
        }
    }
}

private static synchronized void myPrint(String s) {
    COUNTER++;
    System.out.print(s);
    if (COUNTER == STEP) {
        COUNTER = 0;
        System.out.println();
    }
}
damianem
  • Rejestracja:prawie 8 lat
  • Ostatnio:4 miesiące
  • Postów:205
1
  • Ustaw początkową wartość semafora c na 3
  • Wymagaj w pętli C na początku dwóch tokenów -> po pierwszym wypisanym C wartość semafora spadnie do 1 -> pierwsze A doda 1, będzie w sumie 2 co sprawi, że CBA wypisze się jeszcze raz. Drugie A znowu doda jeden do c, ale tym razem będzie to za mało żeby znowu uruchomić sekwencję CBA (czyli dobrze, bo teraz chcemy przejść do DDE).
  • Z pętli D wywal c.release() -> zamiast tego dodaj na końcu pętli E c.release(2) żeby przywrócić stan początkowy przed kolejną linijką
  • Pętla E powinna dodawać do d wartości tak, żeby wymusić wypisanie drugiego D, czyli coś takiego:
Kopiuj
                // E
                for (int i = 0; i < COUNT; i++) {
                    e.acquire();
                    d.release(2);
                    e.acquire();
                    myPrint("E ");
                    c.release(2);
                }
GO
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:12
0
damianem napisał(a):
  • Ustaw początkową wartość semafora c na 3
  • Wymagaj w pętli C na początku dwóch tokenów -> po pierwszym wypisanym C wartość semafora spadnie do 1 -> pierwsze A doda 1, będzie w sumie 2 co sprawi, że CBA wypisze się jeszcze raz. Drugie A znowu doda jeden do c, ale tym razem będzie to za mało żeby znowu uruchomić sekwencję CBA (czyli dobrze, bo teraz chcemy przejść do DDE).
  • Z pętli D wywal c.release() -> zamiast tego dodaj na końcu pętli E c.release(2) żeby przywrócić stan początkowy przed kolejną linijką
  • Pętla E powinna dodawać do d wartości tak, żeby wymusić wypisanie drugiego D, czyli coś takiego:
Kopiuj
                // E
                for (int i = 0; i < COUNT; i++) {
                    e.acquire();
                    d.release(2);
                    e.acquire();
                    myPrint("E ");
                    c.release(2);
                }

Dzięki za odpowiedz, rozumiem, że kod powinien wyglądać, tak? Pytam się. ponieważ nadal nie wychodzi mi pożądany wynik.
```Java
public final class Controller {

private static final int COUNT = 30;
private static int COUNTER = 0;
private static final int STEP = 9;
private static final Semaphore a = new Semaphore(0, true);
private static final Semaphore b = new Semaphore(0, true);
private static final Semaphore c = new Semaphore(3, true);
private static final Semaphore d = new Semaphore(0, true);
private static final Semaphore e = new Semaphore(0, true);

public static void main(String[] args) {
    new A().start();
    new B().start();
    new C().start();
    new D().start();
    new E().start();
}

private static final class A extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT * 2; i++) {
                a.acquire();
                // b.release();
                  //a.acquire();
                myPrint("A ");
                c.release();
                d.release();
            }
        }
        catch (InterruptedException ex) {
        }
    }
}

private static final class B extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT * 2; i++) {
                b.acquire();
                myPrint("B ");
                a.release();
            }
        }
        catch (InterruptedException ex) {
        }
    }
}

private static final class C extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT * 2; i++) {
                c.acquire();
                myPrint("C ");
                b.release();

            }
        }
        catch (InterruptedException ex) {
        }
    }
}

private static final class D extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT * 2; i++) {
                d.acquire();
                //c.release();
                d.acquire();
                myPrint("D ");
                e.release();
            }
        }
        catch (InterruptedException ex) {
        }
    }
}
private static final class E extends Thread {

    @Override
    public void run() {
        try {
            for (int i = 0; i < COUNT; i++) {
                e.acquire();
                d.release(2);
                e.acquire();
                myPrint("E ");
                c.release(2);
            }
        }
        catch (InterruptedException ex) {
        }
    }
}
private static synchronized void myPrint(String s) {
    COUNTER++;
    System.out.print(s);
    if (COUNTER == STEP) {
        COUNTER = 0;
        System.out.println();
    }
}

}

Kopiuj
edytowany 3x, ostatnio: Gorth
damianem
  • Rejestracja:prawie 8 lat
  • Ostatnio:4 miesiące
  • Postów:205
3

W C zamień c.acquire() na c.acquire(2)

GO
Bardzo dziękuję za pomoc, wszystko świetnie działa!
GO
Mogę zapytać, dlaczego wartość semaforowa c ma wartość 3?
damianem
  • Rejestracja:prawie 8 lat
  • Ostatnio:4 miesiące
  • Postów:205
2

Mogę zapytać, dlaczego wartość semaforowa c ma wartość 3?

Chodzi o to, żeby na końcu pierwszej sekwencji CBA odpalić C ponownie, ale za drugim razem już nie - wtedy chcemy zacząć pisać DDE. Skoro jednak pętla A ma wykonywać za każdym razem ten sam kod to możemy takie zachowanie wymusić kombinując z wartością semafora. Jeśli odpalenie C wymaga 2 wartości a A dodaje jedną, to łatwo policzyć, że przed każdą linijką wartość c powinna wynosić 3 - pierwsze odpalenie C zabiera 2, zostaje 1. Pierwsze odpalenie A dodaje 1, mamy 2. To pozwala na odpalenie C ponownie, c spada do wartości 0 -> drugie A dodaje do c 1, mamy w sumie 1. W tym momencie C się nie odpali, ale za to wartość semafora d osiągnęła 2 co pozwala na rozpoczęcie sekwencji DDE. Na końcu trzeba c podnieść o 2, żeby znowu wartość wynosiła 3.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.