---
# System prepended metadata

title: L4 GRUPA 1

---

# L4 GRUPA 1

## Zadanie 1
:::success
Autor:	Kamil Galik	
:::
```java=
class Filter implements Lock {
    int[] level;
    int[] victim;
    public Filter(int n) {
        level = new int[n];
        victim = new int[n]; // use 1..n-1
        for (int i = 0; i < n; i++) {
            level[i] = 0;
        }
    }
    
    public void lock() {
        int me = ThreadID.get(); // returns 0..n-1
        for (int i = 1; i < n; i++) { // attempt to enter level i
            level[me] = i;
            victim[i] = me;
            // spin while conflicts exist
            while (( ∃ k != me) (level[k] >= i && victim[i] == me)) {};
        }
    }
    
    public void unlock() {
        int me = ThreadID.get();
        level[me] = 0;
    }
}
```
*Fakt:* każdy wątek wykonujący metodę lock() znajduje się na jednym z $n-1$ poziomów, z których ostatni oznacza zajęcie zamka. Na poziomie $n - i$ znajduje się jednocześnie co najwyżej $i$ wątków.

*Uzasadnienie*: 
Zrobimy indukcję po poziomach. Na poziomie 0 trywialnie znajduje się n wątków. Załóżmy indukcyjnie, że na poziomie $j - 1$ (dla $j > 0$) znajduje się co najwyżej $n - j + 1$ wątków. Pokażemy, że na poziom $j$ nie przejdzie przynajmniej 1 wątek.

Załóżmy nie wprost, że na poziomie $j$ znajduje się $n - j + 1$ wątków.
Niech $A$ będzie ostatnim wątkiem, który zapisał zmienną victim na poziomie $j$.
Wtedy dla dowolnego wątku $B$ na poziomie $j$: $Write_B(victim[j] = B)\rightarrow Write_A(victim[j] = A)$
Z kodu widzimy, że: $Write_B(level[B] = j)\rightarrow Write_B(victim[j] = B)\rightarrow Write_A(victim[j] = A)\rightarrow Read_A(level[B])$
Wątek $A$ staje się w takim razie ofiarą i nie mógł wejść na poziom $j$, ponieważ dla każdego wątku $B$: $level[B] >= j$ co jest sprzeczne z tym, że A weszło na poziom $j$.

**Wzajemne wykluczanie:** Wątek wchodzi w sekcję krytyczną, gdy znajduje się na (n-1)-szym poziomie. Niech i = 1. Z faktu przytoczonego powyżej wiemy, że na poziomie n-1 znajduje się co najwyżej 1 wątek, czyli zachodzi własność wzajemnego wykluczania.
## Zadanie 2
:::success
Autor:	Wojciech Pokój	
:::

![](https://i.imgur.com/TAvTyZS.png)

D-d przez odwróconą indukcję po poziomach

Podstawa indukcji: 
Poziom n - 1 posiada tę własność ponieważ jak pokazaliśmy, może tam dotrzeć conajwyżej 1 wątek, więc zagłodzenie na tym poziomie nie występuje

Krok:
Załóżmy nie wprost że A utknął na poziomie i. Z założenie indukcyjnego, po jakimś czasie na wyższych poziomach nie będzie żadnych wątków. Po tym jak A ustawi level[A] = i, wtedy wszystkie wątki oczekujące na niższych poziomach nigdy nie wejdą na poziom i-ty, ponieważ będą zblokowane przez tę wartość.

Ponieważ A będzie jedynym wątkiem który będzie konkurować na poziomie i oraz wyższych więc dostanie w końcu dostęp na poziom wyżej.

Zblokowanie nie nastąpi też gdy 2 wątki A i B utkną na jednym poziomie. Jeden wątek na pewno przejdzie wyżej, ponieważ victim nie może jednocześnie wskazywać na 2 wartości.

Na mocy indukcji algorytm nie posiada własnoci zagłodzenia

Można stąd też wywnioskować że algorytm się nigdy nie zablokuje, ponieważ w końcu zwolnią się poziomy wyżej więc kolejka może zawsze być kontynuowana

## Zadanie 3
:::success
Autor:	Julia Matuszewska	
:::
![](https://i.imgur.com/7ED96PO.png)
```java=
class Filter implements Lock  {
    //informacje o poziomie każdego wątku
    int[] level;
    //informacje o wątku który jako ostatni zgłosił chęć zdobycia poziomu
    int[] victim;
    public Filter(int n) {
        level = new int[n];
        victim = new int[n]; // use 1..n-1
        for (int i = 0; i < n; i++) {
            level[i] = 0;
        }
    }
    public void lock() {
        int me = ThreadID.get(); // returns 0..n-1
        for (int i = 1; i < n; i++) { // attempt to enter level i
            level[me] = i;
            victim[i] = me;
            // spin while conflicts exist
            // inny wątek jest na wyższym lub równym poziomie
            // i nasz wątek jako ostatni zgłosił chęć zdobycia poziomu
            while (( ∃ k != me) (level[k] >= i && victim[i] == me)) {};
        }
    }
    public void unlock() {
        int me = ThreadID.get();
        level[me] = 0; //zerujemy poziom wątku
    }
}
```
:::info
![](https://i.imgur.com/A2j2Pzl.png)
:::

SW - sekcja wejściowa (instrukcje przypisania `level[me]` i `victim[i]`)
Załóżmy, że uruchamiamy algorytm z użyciem 3 wątków

me = ThreadID.get();

---

1. Wątek 1 wchodzi do `lock` i wykonuje SW (`level[me] = 1`, `victim[1] = me`) i zostaje wywłaszczony
2. W wątku 2 to samo co w kroku 1., jest ustawiony jako `victim`, zostaje wywłaszczony
3. W wątku 3 to samo co w kroku 2., jest ustawiony jako `victim`, zostaje wywłaszczony
4. Wątek 2 zostaje kontynuowany, wchodzi na wyższy poziom (`victim[1] = 3`). Warunek czekania w pętli `while` (linijka 21) nie jest spełniony, więc może przejść przez wszystkie następne poziomy, co też mu się udaje i wchodzi do CS. Po wykonaniu znów wykonuje `lock()`. Jest ustawiony jako `victim` i zostaje wywłaszczony.
5. W wątku 3 to samo co w kroku 4.

Może wystąpić sytuacja taka, że kroki 4 i 5 będą powtarzały się dowolną liczbę razy, zwiększając liczbę udanych wejść na wyższy poziom dla wątków 2 i 3, i nie zmieniając dla wątku 1, zatem ta różnica dla wątku 1 i któregoś z wątków 2 i 3 może być dowolnie duża, nie istnieje taka stała $r$, że operacja przejścia na kolejny poziom ma własność $r$-ograniczonego czekania

Niech $LU$ oznacza osiągnięcie nowego poziomu

$D_0^0 \rightarrow D_1^0 \rightarrow D_2^0 \rightarrow LU_1^0 \rightarrow D_1^1 \rightarrow LU_2^0 \rightarrow D_2^1 \rightarrow \dots \rightarrow  D_1^r \rightarrow D_2^r \rightarrow LU_1^r \rightarrow LU_0^0$

z czego mamy

$D_0^0 \rightarrow D_1^0$
$LU_1^r \rightarrow LU_0^0$

## Zadanie 4
:::success
Autor: Wiktor Bukowski		
:::
### 1. 
```java=
public void lock() {
 flag[i] = true; 
 victim = i;
 while (flag[j] && victim == i) {};
}
public void unlock() {
 flag[i] = false; 
}
```

Oznaczmy jako A ten z wątków, który jako pierwszy wykonał sekcję wejściową. Drugi z nich oznaczmy jako B. Załóżmy, że B jako pierwszy wykonał sekcję krytyczną.
$D_A \rightarrow D_B$
$CS_B \rightarrow CS_A$
$D_A \rightarrow W_A \rightarrow CS_A$
$D_B \rightarrow W_B \rightarrow CS_B$
Wtedy z przechodniości $\rightarrow$:
$D_A \rightarrow D_B \rightarrow CS_B \rightarrow CS_A$

Jeśli B jako drugi wykonał sekcję wejściową, to ustawił zmienną `victim` na samego siebie, przez co musiał potem czekać w sekcji oczekiwania do wykonania przez A sekcji krytycznej i zmiany jego flagi. W związku z tym B nie mógł wykonać sekcji krytycznej przed A.

### 2. 
Ustalmy, że wątek A jako pierwszy wykonał ustawienie flagi. Natomiast niech wątek B jako pierwszy wykona ustawienie zmiennej `victim`. Następnie wątek A nadpisze tę zmienną, dzięki czemu B będzie mógł wejść do sekcji krytycznej.

### 3.

#### a) 
Oba wątki odczytają to samo niezależnie od kolejności, a więc nie ma możliwości rozróżnienia, który tak naprawdę wykonał tę instrukcję szybciej.

### b)
Jeśli oba zapisy nastąpią jeden po drugim, a dopiero potem oba wątki przejdą do kolejnych instrukcji, to nie do rozróżnienia będzie, który wątek jako pierwszy zapisał do swojej komórki.

### c)
Gdy drugi wątek nadpisze wspólną komórkę, stan zamka będzie nierozróżnialny ze stanem, w którym pierwszy wątek w ogóle nie próbował zdobyć blokady. W związku z tym wątek drugi może cały czas wykonywać instrukcje i dostać się do sekcji krytycznej.


## Zadanie 5
:::success
Autor:	Mateusz Kisiel	
:::
![](https://i.imgur.com/j0fXBmE.png)

![](https://i.imgur.com/ZORA9NN.png)

Sekwencyjny porządek:
```
r.write(1)
r.read(1)
r.write(2)
r.read(2)
```
![](https://i.imgur.com/OhDvX9e.png)
Sekwencyjny porządek:
```
r.write(2)
r.write(1)
r.read(1)
r.read(1)
```
![](https://i.imgur.com/4VN6gqu.png)
Po wykonaniu jako pierwsze `p.enq(x)` nie może zostać zwrócone y z `p.deq()`

![](https://i.imgur.com/afcnVu8.png)


## Zadanie 6
:::success
Autor:	Marcin Wróbel	
:::
![](https://i.imgur.com/HMRxnFI.png)

![](https://i.imgur.com/CgZZTyf.png)


### Diagram 1
![](https://i.imgur.com/7eKm97d.png)
Historia H
```
B r.write(1) 
A r.read()
C r.write(2)
A r: 1
C r: void
B r: void
B r.read()
B r: 2
```

Legalna sekwencyjna historia S
```
B r.write(1)
B r: void
A r.read()
A r: 1
C r.write(2)
C r: void
B r.read()
B r: 2
```

$\rightarrow_H=$
$\{r.read(1) \rightarrow r.read(2)$
$r.write(1) \rightarrow r.read(2)$
$r.write(2) \rightarrow r.read(2)\}$

$\rightarrow_S=$
$\{r.write(1) \rightarrow r.read(1)$
$r.read(1) \rightarrow r.write(2)$
$r.write(2) \rightarrow r.read(2)\}$

### Diagram 2
![](https://i.imgur.com/OKRPxxM.png)
Historia H
```
B r.write(1)
A r.read()
C r.write(2)
A r: 1
C r: void
B r: void
B r.read()
B r: 1
```

Legalna sekwencyjna historia S
```
C r.write(2)
C r: void
B r.write(1)
B r: void
A r.read()
A r: 1
B r.read()
B r: 1
```

$\rightarrow_H=$
$\{p.read(1) \rightarrow r.read(1)$
$p.write(1) \rightarrow r.read(1)$
$p.write(2) \rightarrow r.read(1)\}$


$\rightarrow_S=$
$\{r.write(2) \rightarrow r.write(1)$
$r.write(1) \rightarrow r.read(1)$
$r.read(1) \rightarrow r.read(1)\}$

### Diagram 3
![](https://i.imgur.com/TlK9Adc.png)


Historia H
```
A p.enq(x)
A p: void
B p.enq(y)
B p: void
A p.deq()
A p: y
```

Historia H nie odpowiada żadnej legalnej sekwencyjnej historii S, ponieważ 
mamy $p.enq(x) \rightarrow p.enq(y) \rightarrow p.deq(y)$
Po wykonaniu $p.enq(y)$ kolejka będzie zawierać x jako pierwszy element, więc p.deq() zwróci x, a nie y.

$\rightarrow_H=$
$\{p.enq(x) \rightarrow p.enq(y)$
$p.enq(y) \rightarrow p.deq(y)\}$
### Diagram 4
![](https://i.imgur.com/pOFDmcY.png)

Historia H
```
A p.enq(x)
A p: void
B q.enq(y)
B q: void
A q.enq(x)
A q: void
B p.enq(y)
B p: void
A p.deq()
A p: y
B q.deq()
B q: x
```

Historia H nie odpowiada żadnej legalnej sekwencyjnej historii S, ponieważ 
mamy $p.enq(x) \rightarrow p.enq(y) \rightarrow p.deq(y)$
Po wykonaniu $p.enq(y)$ kolejka będzie zawierać x jako pierwszy element, więc p.deq() zwróci x, a nie y.

$\rightarrow_H=$
$\{p.enq(x) \rightarrow q.enq(y)$
$q.enq(y) \rightarrow q.enq(x)$
$q.enq(x) \rightarrow p.enq(y)$
$p.enq(y) \rightarrow p.deq(y)$
$p.deq(y) \rightarrow q.deq(x)\}$