Zadanie z synchronizacji wielu wątków

Zadanie z synchronizacji wielu wątków
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 dni
  • Postów:354
0

Mam takie zadanie:

Jest most o długości d i nośności w. Na niego będą wjeżdżać auta, a każde z nich ma być reprezentowane przez osobny wątek, auta mają swoją wagę i długość. Pojazdy przed wjazdem mają się kolejkować (wszystkich nie może być więcej niż 25), przy odpowiednich warunkach wjeżdżać na most (musi być wolne miejsce i nie można przekroczyć nośności), poruszać się po nim (nie można wyprzedzać, auta jada tylko w jedna stronę oraz z tego mostu zjeżdżać i kończyć swój żywot. Mogą być to metody enter(), move() i exit() klasy Samochod.

Proszę o pomoc, bo nawet nie jestem w stanie stworzyć konceptu, na razie pomysł miałem taki.
Klasa Bridge (przechowuje wszystkie zmienne związane z mostem, wie ile jest aktualnie pojazdów sume ich mas itd)
Klasa Car dziedziczącą po Thread (osobne watki reprezentujace auta, kazdy z nich ma dostep do Bridge ktory jest jeden i probuje z nim się komunikować)
Klasa BridgeSimulation która jest nadrzędna, generuje watki i dodaje je do kolejek.

no i tak, generujemy wątki i dajemy je do BlockedQueue z ograniczonym rozmiarem do 25
Gdy wątek jest pierwszyw kolejce odpalamy go poprzez .start()
Próbuje wjechać na most, gdy jest to możliwe to na niego wjeżdza //enter()
Przemieszcza sie po nim nie wjezdzajac w inne auta //move()
gdy dojedzie do konca to umiera //exit()

Gdy próbowałem robic ten kod, uzywać synchornized to kończyło się tak, że albo nic nie wjeżdzało na most, albo przesuwało się jedno auto a dopiero potem kolejne, nie mam też pojecia jak zrobić tak, żeby kilka auto przejeżdżało po moscie, patrzac na siebie czy ze soba nie koliduja. (można np. zrobic tablice i sprawdzac pozycje, ale nie wiem jak synchornizować te wątki)


Competitive Google searcher
edytowany 3x, ostatnio: Riddle
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 8 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10074
1

Współbieżność to jedna z najtrudniejszych rzeczy do ogarnięcia jaką znam w programowaniu. Nie wiem czy jest sens to robić na wątkach.

S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 dni
  • Postów:354
0

Też nie widzę sensu tego robić na wątkach, niestety to zadanie na studia :(


Competitive Google searcher
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 8 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10074
1

No to jeśli dobrze rozumiem to zadanie, to ten "most" ma symbolizować kolejkę thread-safe, do której "wjazd" ma tylko określona liczba wątków (określona na podstawie tych dwóch liczb, czyli długość i waga).

Spodziewam się że jeśli samochody to mają być wątki, to widzę to tak:

  • Albo wszystkie wątki startują od razu (np 1000 wątków się odpala od razu), wszystkie próbują coś wsadzić do kolejki, ale tylko 25 pierwszych z nich da radę pozostałe będą blocked dopóki miejsce w kolejce się nie zwolni
  • Albo tak jak mówisz, że wątki domyślnie nie są odpalone, i dopiero jak jest miejsce w nich to odpalasz .start().

W ogóle to zadanie jest jakoś dziwnie napisane.

Nawet nie do końca jest jasne co ten program ma robić na tak na prawdę- no dobra, ma mieć wątki które wołają jakieś metody enter(), move() ale co te metody niby mają robić? Tylko się wywołać i nic?

edytowany 1x, ostatnio: Riddle
PI
  • Rejestracja:ponad 9 lat
  • Ostatnio:4 miesiące
  • Postów:2787
0

Brzmi ciężko.

Pytanie - skąd wiadomo w którą stronę samochód jedzie? W sensie zakładając układ współrzędnych, i że samochód jest obecnie na polu (x,y) = (2,3), to na jakie pola może się poruszyć?

Myślę, że pierwsze co bym zrobił to mając dane o obecnych współrzędnych samochodu (2,3), oznaczył każde potencjalne pole, na które ten samochód może się poruszyć (czyli np (3,3), (1,3), (2,4), (2,2)) jako "ostrzeżone" dla reszty, albo przynajmniej już na takie, które miałoby w sobie locka (owy "synchronized" - obejmujący jedynie takie "pole z ostrzeżeniem").

EDIT:
Dobra, nie doczytałem że to most, czyli poruszamy się tylko w jednym wymiarze. No to lekka modyfikacja tego co napisałem wyżej.

edytowany 1x, ostatnio: Pinek
Riddle
@Pinek: To chyba ma być jednowymiarowe.
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 dni
  • Postów:354
0
Riddle napisał(a):

Nawet nie do końca jest jasne co ten program ma robić na tak na prawdę- no dobra, ma mieć wątki które wołają jakieś metody enter(), move() ale co te metody niby mają robić? Tylko się wywołać i nic?

metoda enter() ma wprowadzać na most, a move() symuloawć przemieszczanie się po nim


Competitive Google searcher
edytowany 1x, ostatnio: Riddle
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 12 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
0

Zadanie prawie spoko, poza jednym zdaniem dla mnie:
Przemieszcza sie po nim nie wjezdzajac w inne auta //move()

Jak można wjechać w inne auto przy tak podanym zadaniu?


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 1x, ostatnio: jarekr000000
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 dni
  • Postów:354
0

To jest moja pafraza zadania, żeby były same konkrety, bo w oryginale jest lanie wody i jeszcze fragmenty o wizualizacji


Competitive Google searcher
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 12 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
0

Bo widzę dwie możliwości - prosta: auto jest albo przed mostem, albo na moście i za mostem. bardziej skomplikowana: auto znajduje się w jakimś punkcie p długości mostu.


jeden i pół terabajta powinno wystarczyć każdemu
S7
Auto znajduje się na jakieś długości p mostu, ma także swoją długość, ma być to wizualizowane mniej więcej [**aa*bbbb*c**]
SL
  • Rejestracja:około 7 lat
  • Ostatnio:około 6 godzin
  • Postów:896
0
Suchy702 napisał(a):

Gdy próbowałem robic ten kod, uzywać synchornized

synchronized to jest uproszczony lock zero jedynkowy: albo coś ma zasób albo nie. W tym wypadku chcesz użyć https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Semaphore.html . permits to jest maksymalna dopuszczalna masa mostu.

Miang
  • Rejestracja:około 7 lat
  • Ostatnio:2 minuty
  • Postów:1674
0
Suchy702 napisał(a):

Próbuje wjechać na most, gdy jest to możliwe to na niego wjeżdza //enter()

Gdy próbowałem robic ten kod, uzywać synchornized to kończyło się tak, że albo nic nie wjeżdzało na most, albo przesuwało się jedno auto a dopiero potem kolejne, nie mam też pojecia jak zrobić tak, żeby kilka auto przejeżdżało po moscie, patrzac na siebie czy ze soba nie koliduja. (można np. zrobic tablice i sprawdzac pozycje, ale nie wiem jak synchornizować te wątki)

a jak sprawdzasz czy jest możliwy ten wjazd na most?


dzisiaj programiści uwielbiają przepisywać kod z jednego języka do drugiego, tylko po to by z projektem nadal stać w miejscu ale na nowej technologii
S7
no jezeli auto wjezdza na most to aktualizuje aktualna wage, gdy zjezdza tez ja zmienia. Ponadto ma swoja aktualną pozycje w tablicy, wiec mozna sprawdzic czy "jest miejsce" na moscie
Miang
ale jak sprawdzasz PRZED wjazdem na most czy może wjechać?
S7
no sprawdzam czy aktualna waga na moscie + waga potencjalnego samochodu nie przekraczaja limutu
Miang
a dlaczego dla drugiego samochodu z kolejki to sprawdzenie daje wynik ze przekracza?
S7
Nie rozumiem, kod ponizszy kod powinien tlumaczyc jak probuje to zrobic
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 dni
  • Postów:354
0

Popełniłem taki kod:

Kopiuj
package MultiThreading;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

class Bridge {
    private int length;
    private int capacity;
    private int currentLoad;
    private char[] bridgeState;

    public Bridge(int length, int capacity) {
        this.length = length;
        this.capacity = capacity;
        this.currentLoad = 0;
        this.bridgeState = new char[length];
        initializeBridgeState();
    }

    private void initializeBridgeState() {
        for (int i = 0; i < length; i++) {
            bridgeState[i] = '*';
        }
    }

    public boolean canGo(Car car){
        return currentLoad + car.getWeight() <= capacity && bridgeState[0] == '*';
    }

    public char getPosStatus(int idx){
        return bridgeState[idx];
    }

    public void changePosStatus(int idx, char ch){
        bridgeState[idx] = ch;
    }

    public boolean passedBridge(int position){
        return position == length-1;
    }

    public void displayBridgeState() {
        System.out.println(bridgeState);
    }
}

class Car extends Thread {
    private Bridge bridge;
    private int weight;
    private char name;
    private int position;

    public Car(Bridge bridge, int weight, char name) {
        this.bridge = bridge;
        this.weight = weight;
        this.name = name;
        this.position = 0;
    }

    public int getWeight() {
        return weight;
    }

    private boolean canMove(){
        return bridge.getPosStatus(position+1) == '*';
    }

    public void move(){
        if (canMove()){
            bridge.changePosStatus(position, '*');
            bridge.changePosStatus(position+1, name);
            bridge.displayBridgeState();
        }
    }

    @Override
    public void run() {
        System.out.println("Wlasnie wjechal pojazd: " + name);
        while (!bridge.passedBridge(position)) {
            move();
        }
    }
}

public class BridgeSimulation {
    public static void main(String[] args) {
        Bridge bridge = new Bridge(10, 200);
        BlockingQueue<Car> queue = new LinkedBlockingQueue<>(25);

        for (int i = 0; i < 5; i++){
            queue.add(new Car(bridge, 1, (char) ('a' + i)));
        }

        while (!queue.isEmpty()){
            if (bridge.canGo(queue.peek())){
                Car actCar = queue.poll();
                assert actCar != null;
                actCar.start();
            }

        }
    }
}

Dostaje takie wyjscie, za kazdym razem kolejnosc jest inna:

Kopiuj
Wlasnie wjechal pojazd: b
Wlasnie wjechal pojazd: e
Wlasnie wjechal pojazd: c
Wlasnie wjechal pojazd: d
Wlasnie wjechal pojazd: a
*b********

Dlaczego watki wygladaja jakby nie uruchamialy sie po kolei? I jak zrobic zeby robily to wlasnie po kolei.
tylko jedno auto sie poruszylo i stoi w miejscu, nie jedzie dalej, dlaczego?

Dla uproszczenia dlugosc kazdego samochodu to 1, waga tak samo wiec nie gra roli


Competitive Google searcher
Miang
gdzie uaktualniasz position dla samochodu?
S7
Rzeczywiście tego nie robie, dziękuje
Miang
  • Rejestracja:około 7 lat
  • Ostatnio:2 minuty
  • Postów:1674
2

a dlaczego miałyby działać po kolei skoro to są osobne wątki?


dzisiaj programiści uwielbiają przepisywać kod z jednego języka do drugiego, tylko po to by z projektem nadal stać w miejscu ale na nowej technologii
Riddle
Wiekopomna chwila. Właśnie pierwszy raz dałem plusa osobie @Miang
S7
okej, jak dodam sleep(100) to zaczyna to dzialac mniej wiecej tak jak mysle
S7
  • Rejestracja:prawie 5 lat
  • Ostatnio:4 dni
  • Postów:354
0

Po dodaniu sleep(100) w

Kopiuj
        //glowna petla
        while (!queue.isEmpty()){
            sleep(100);
            if (bridge.canGo(queue.peek())){
                Car actCar = queue.poll();
                assert actCar != null;
                actCar.start();
            }
        }
Kopiuj
    //run w klasie Car
    @Override
    public void run() {
        System.out.println("Wlasnie wjechal pojazd: " + name);
        while (!bridge.passedBridge(position)) {
            move();
            try {
                sleep(100); // Dodatkowe oczekiwanie dla czytelności wyjścia
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

auta zaczynaja uruchamiac sie po kolei, natomiast dalej dochodzi tylko do jednego przesuniecia

Kopiuj
Wlasnie wjechal pojazd: a
*a********
Wlasnie wjechal pojazd: b
Wlasnie wjechal pojazd: c
Wlasnie wjechal pojazd: d
Wlasnie wjechal pojazd: e

Competitive Google searcher
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 8 godzin
  • Lokalizacja:Laska, z Polski
  • Postów:10074
2

@Suchy702: Ale to nie ma sensu, bo to jest normalne w wątkach że one się nie uruchomią po kolei - na tym polega współbieżność. Z resztą, co to miałoby znaczyć "po kolei", przecież kod wątkach działa równocześnie.

edytowany 1x, ostatnio: Riddle
S7
ale uruchomienie nie działa równocześnie, tylko po kolei
Riddle
@Suchy702: Jeśli masz zadanie z wątków, i ich celem jest to, żebyś nauczył się wątków, to oswój się z myślą że w wątkach nie ma czegoś takiego jak "kolejność". One działają równocześnie.
FD
  • Rejestracja:ponad rok
  • Ostatnio:ponad rok
  • Postów:39
0

Wątki nie są trzymane w queue, która kolejka może być czytana od tyłu lub od przodu jako lifo i fifo, wtedy by się uruchamiały jeden po drugim.

Ale w systemie operacyjnym są przetrzymywane w red black tree, więc jak dajesz syscall utworzenia thread, czyli clone, to wtedy dodajesz do samo balansującego drzewa, jak jakaś inna aplikacja zrobi wątek czy uruchomi proces to znowu przebiega balans drzewa na podstawie wag.
To jest też nazywane na linuxie completly fair scheduling.

Różnie może się te drzewo zbalansować i potem jest dequeue z tego drzewa, balansowane jest na podstawie wag, kernelowe thready są wyżej w rankingu i nie ma rozróżnienia między procesami i wątkami.

Żeby jako tako synchronizację zrobić, wykorzystałeś sleep, który działa w miarę bo poczekałeś aż wystartuje wątek pierwszy i dopiero następny utworzyłeś itp.

Można też jakieś tricki ze state machine zrobić i mutexami, gdzie wątek robi mutexa, ale jak nie jest maszyna stanów na jego wątku to odblokowuje i idzie czekać, a jak jest to blokuje, wykonuje swoje modyfikując uwspólnione struktury danych, inkrementuje maszynę stanów do następnego pojazdu i wychodzi.
Ale to też problemów dużo rodzi, bo nawet dokładnej treści zadania nie wiadomo, aczkolwiek możesz też to jakoś wykorzystać.

Będziesz musiał na pewno trochę pokombinować, używaj to co masz od semafor, mutexów, atomic operations, czy samych struktur thread safe, coś wymyślisz.

Miang
to jak są trzymane to chyba nieudokumentowana właściwość która inaczej zadziała na innym systemie. A w zadaniu chyba chodzi o to żeby zgodnie z regułami sztuki je wykonać, Przypuszczam ze było powiedziane na zajęciach co należy użyć ;) Nie wiem czy w javowych wątkach jest jakiś odpowiednik sygnałów ?
FD
@Miang: no tak jest, w sumie nawet od 6.0 wersji dali ulepszoną wersję schedulera, która dość dużo z 20% dawała performancu, można też ręcznie sobie zmienić, na windowsie gorzej bo tam trudniej coś zmodyfikować. A java też jakoś tam po swojemu syscalle systemowe wywołuje, sygnały potrafią budzić wątki to można nawet uśpić wszystkie i budzić tylko wybrane do pracy, ale sygnały są na linuxie, na windowsie nie ma, jako że nie znam aż tak javy, a java jest przenośna to jak nie ma odpowiednika czegoś na innych systemach, to powinno nie być, ale kto wie czy nie wymyślili czegoś:>
SZ
  • Rejestracja:prawie 2 lata
  • Ostatnio:4 miesiące
  • Postów:52
1

Spróbuj private volatile char[] bridgestate. Prawdopodobnie dochodzi do hoisting na głównej petli. Ale jak usuniesz sleep to i tak pojawią się znowu problemy. Może semafor z 25 uprawnieniami i atomic reference do stanu mostu jako record(zapis i odczyt).

edytowany 1x, ostatnio: Riddle
c3r
  • Rejestracja:ponad 7 lat
  • Ostatnio:około rok
  • Lokalizacja:Kraków
  • Postów:18
1

Szczerze mówiąc, to zadanie brzmi jak typowy problem semaforowy, gdzie procesy (auta) walczą o dostęp do zasobów (waga i miejsce na moście). Ja bym podszedł do tego w sten sposób żeby rozszerzyć (skomponować) klasę z java.util.concurrent.Semaphore i przeciążyć metody acquire() i release().

Zobacz pozostałe 7 komentarzy
Miang
widziałeś kiedyś wjazd na most w rzeczywistości?
Riddle
@Miang: za bardzo się skupiasz na analogii. Może jeszcze powiesz że do klasy Car musimy dodać pola koła, podwozie, skrzynia biegów, przednia szyba, a do mostu to wiadomo, podpory i zróbmy też klasę rzeka, bo mosty są nad rzeką.
Riddle
W nawiasie jest wyjaśnione co to znaczy kolejkować - wszystkich nie może być więcej niż 25. Odnośnie kolejności nie ma specyfikacji. Dodawanie na siłę kolejnosci bo ktoś użył słowa "most" to moim zdaniem już niepotrzebna komplikacja. Rozwiązanie od @c3r jest w porządku.
Miang
prowadzący jakieś zajęcia: podam problem ze świata rzeczywistego nie będę musiał opisywać tak dokładnie, @Riddle : potrzymaj mi komentarz
Riddle
@Miang: Jeśli prawdą by było, że pojazdy mają wjeżdżać na most po kolei (tak jak na most), i mają jechać mostem po kolei bez wyprzedzania tak jak na moście, i mają się zjechać z mostu po kolei tak jak na moście - to zastanów się: Po kiego kija miałyby być tutaj wątki? ;| Przecież jeśli one wszystkie miałyby wjechać, jechać i wyjechać po kolei, to załatwiłby to zwykły while bez żadnego wątku. W ogóle współbieżność by tu nie była użyta. W takim rozwiązaniu w każdym momencie maksymalnie jeden wątek by działał.

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.