---
# System prepended metadata

title: L13 - GRUPA 1

---

# L13 - GRUPA 1

## Zadanie 1
:::success
Autor:	Wiktor Bukowski	
:::

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


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

Powody niepowodzeń `compareAndSet()`:
- linijka 16: inny wątek ustawił się jako pierwszy w Exchangerze
- linijka 24: jakiś wątek zdążył ustawić się jako drugi w exchangerze, pomimo timeoutu (a więc zakończymy wywołanie z sukcesem)
- linijka 34: inny wątek ustawił się jako drugi w Exchangerze 

**Dlaczego w pewnych dwóch miejscach w kodzie ustawia się zmienną slot przy pomocy set() a nie compareAndSet()?**
Ponieważ tylko jeden wątek może wykonać operację "zwolnienia" Exchangera, a więc może to zrobić bezwarunkowo.

## Zadanie 2
:::success
Autor:	Tomasz Wołczański	
:::
![](https://i.imgur.com/2oU99dT.png)

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

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

Klasa `RangePolicy` odpowiada za dynamiczne ustalanie zakresu, z którego będą losowane indeksy tablicy eliminacji. Zakres powinien być dostosowany do liczby wątków; najprostsza polityka polega na zmniejszaniu zakresu, gdy liczba wymian zakończonych niepowodzeniem zwiększa się (`recordEliminationTimeout`) i zwiększaniu zakresu, gdy zwiększa się liczba wymian zakończonych sukcesem (`recordEliminationSuccess`).

Wywołania metod `push` i `pop`, które kończą się po wywołaniu `tryPush` lub `tryPop` mogą zostać zlinearyzowane tak, jak w `LockFreeStack`. Punkty linearyzacji wywołań zakończonych eliminacją są takie same, jak punkty linearyzacji wywołań `exchange` zakończonych sukcesem.

## Zadanie 3
:::success
Autor:	Wojciech Pokój	
:::

Opisz w sposób wysokopoziomowy (tzn. bez
odwoływania się do kodu) algorytm implementowany przez metodę
getAndIncrement() klasy CombiningTree.


Każdy wątek zaczyna z przypisanego do siebie liścia z pełnego drzewa binarnego.

Wątek podróżuje do góry drzewa dopuki nie napotka węzła które jest już zajęte. Jeżeli węzeł jeszcze nie został zablokowany, tj wątek szybszy jeszcze czeka na inne wątki to blokujemy węzeł na czas zliczania, wpp czekamy aż tamten wątek skończy pracę nad swoim wywołaniem getAndIncrement i idziemy dalej do góry.

Jeśli dotrze do węzła które jest już zajęte to zbiera informację o aktualizacji licznika od wątków które przegrały na poprzednich poziomach i połączony stan umieszcza w polu value węzła w którym przegrał.

Jeśli dotrze do korzenia drzewa to aktualizuje w nim wartość licznika.

Gdy dostanie spowrotem zaktualizowaną wartość licznika to dystrybuuje zaktualizowane wartości wdół aż do liścia z którego przyszedł, po czym zwraca z nowym licznikiem.


## Zadanie 4
:::success
Autor:	Mikołaj Depta	
:::

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

Flaga `locked` pełni rolę jednego z dwóch zamków zakładanych na węzły drzewa podczas operacji na nim. Jest to zamek zakładany podczas okresów kiedy węzeł może być potencjalnie długo niedostępny bo np. wątek wykonuje oprację `combine` na gałęzie drzewa do której on należy.

![](https://i.imgur.com/xiPXukW.png)
![](https://i.imgur.com/9rvrJtB.png)
![](https://i.imgur.com/4RHvnGg.png)
![](https://i.imgur.com/0PH8Pxr.png)
![](https://i.imgur.com/t02CtBr.png)

1.1. `precombine` - Rozpatrzmy wątek W, gdzie flaga te jest podniesiona. Może być tak, że wcześniejsza "iteracja" naszego algorytmu jeszcze się nie skończyła. Może być, że szybki wątek jest w czasie wykonywania combine po przejściu przez W lub jest w trakcie wracania i wykonywania `distribute` albo w przypadku gdy w wątku W doszło do spotkania dwóch wątków, wolny wątek nie odczytał wartości, którą szybszy wątek wpisał do result.
1.2. `combine` - Ponownie rozpatrzmy wątek W, gdzie ta flaga jest poniesiona. Oznacza to, że wątek szybki przechodząc po gałęzi drzewa do węzłą `last` został zarzymany przez wątek wolny rywalizujący o węzeł W jeszcze nie wykonał swoich operacji `combine` i `op` - to znaczy, nie wpisał wartości sumy z węzłów ze swojego poddrzewa do `secondValue`.

2. Metody `op` i `distribute` operują już na zablokowanych gałęziach drzewa schodząc po nich na dół.

3. Wpływ locked na inne wątki
`precombine` - jeśli jesteśmy drugim wątkiem to chcemy, żeby szybszy poczekał aż obliczymy wartość sumy z naszego poddrzewa.
`combine` - chcemy zająć zamki na całej gałęzi drzewa po której przeszliśmy precombine - nie chcemy, żeby nowy wątek wykonujący precombine spóźnione od teraz cokolwiek zmieniał.
`op` - zamka dotykamy przy dwóch okazjach: 
- raz - tylko gdy byliśmy wolniejszym wątkiem i właśnie skończyliśmy przechodzić nasze poddrzewo z kroku combine i ustawiamy wartość secondValue na wartość obliczonej sumy.
- dwa - skończyliśmy czekanie na powrót wątku szybszego, odczytujemy wartość którą nam zostawił i zwracamy.
`distribute` - i wykonywaliśmy `combine` i wracamy z wartością na dół. Jeśli w danym węźle nie było rywalizacji (stan FIRST), to zwalniamy sami zamek i idziemy dalej. W przypadku gdy do rywalizacji doszło chcemy zostawić zwolnienie zamku czekającemu wolnemu wątkowi, żeby żadne przyszłe szybkie iteracje `precombine`, `combine`, `op` i `distribute` przypadkiem nie nadpisały mu wartości result obliczonej przez aktualne wykonanie.

:::info
Pozostałe zadania uznajemy za bonusowe.
:::


## Zadanie 5
Exercise 12.2. Implement a trinary CombiningTree , that is, one that allows up to three
threads coming from three subtrees to combine at a given node. Can you estimate the
advantages and disadvantages of such a tree when compared with a binary combining
tree?

:::danger
Autor: Mikołaj Depta		
:::

:::info
Przedstawiane rozwiązanie zaczerpnięto z https://github.com/wolvre/trinary-combining-tree/blob/master/src/Combine/TriTree.java
:::

```java
public class TriTree {
  volatile int stamp = 0;
  final static int THREADS = 12;
  final static int TRIES = 1024 * 1024;
  static boolean[] test = new boolean[THREADS * TRIES];
    
  TriNode[] leaf;
  
  /** Creates a new instance of Combine */
  public TriTree(int size) { //size=27
    TriNode[] nodes = new TriNode[size/2];
    nodes[0] = new TriNode();
    for (int i = 1; i < nodes.length; i++) {
      nodes[i] = new TriNode(nodes[(i-1)/3], i);
    }
    leaf = new TriNode[(size + 1)/3];
    for (int i = 0; i < leaf.length; i++) {
      leaf[i] = nodes[nodes.length - i - 1];
    }
  }
  
  public int getAndIncrement() throws InterruptedException {
    Stack<TriNode> stack = new Stack<TriNode>();
    int tid = ThreadID.get();
    TriNode myLeaf = leaf[tid % 9];//[tid / 3];
    TriNode node = myLeaf;
    // phase one
    while (node.precombine()) {
      //System.out.printf("%d: Thread %d precombining done at Node %d.\n", stamp++, tid, node.nid);
      node = node.parent;
    }
    TriNode stop = node;
    //System.out.printf("%d: Thread %d stops precombining at Node %d.\n", stamp++, tid, stop.nid);
    // phase two
    node = myLeaf;
    int combined = 1;
    while (node != stop) {
      combined = node.combine(combined);
      // System.out.printf("%d: Thread %d combining done at Node %d.\n", stamp++, tid, node.nid);
      stack.push(node);
      node = node.parent;
    }
    // phase 3  
    int prior = stop.op(combined);
    if (test[prior]) {
        System.out.printf("ERROR duplicate value %d by Thread %d, Node %d\n", prior, tid, stop.nid);
        return prior;
    }
    else
        test[prior] = true;
    //System.out.printf("%d: Thread %d operation done at Node %d.\n", stamp++, tid, stop.nid);

    // phase 4
    while (!stack.empty()) {
      node = stack.pop();
      node.distribute(prior);
      //System.out.printf("%d: Thread %d distribution done at Node %d.\n", stamp++, tid, node.nid);
    }
    //System.out.printf("%d: Thread %d returns %d.\n", stamp++, tid, prior);
    return prior;
  }
  
}
```

## Zadanie 6
Exercise 12.3. Implement a CombiningTree using Exchanger objects to perform the
coordination among threads ascending and descending the tree. What are the possi-
ble disadvantages of your construction when compared to the CombiningTree class
presented in Section 12.3?


:::danger
Autor:	
:::

## Zadanie 7

Exercise 12.4. Implement the cyclic array-based shared pool described in Sec-
tion 12.2 using two simple counters and a ReentrantLock per array entry.

:::danger
Autor:	
:::
