---
# System prepended metadata

title: Untitled

---

## Systemy Operacyjne - Lista 10

### Zadanie 1
![](https://i.imgur.com/Le0qOIY.png)

*Przetwarzanie równoległe (ang. parallel)* - polega na równoległym wykonywaniu wielu zadań. Np wykorzystując 4 procesory można wykonywać RÓWNOLEGLE 4 zadania (no wiadomo procesor ma rdzenie itd)

*Przetwarzanie współbieżne (ang. concurrent)* - polega na wykonywaniu wielu zadań JEDNOCZEŚNIE, ale zadania te są wykonywane przez JEDEN procesor, standardzik, procesy są poprzeplatane, wykonuje się kawałek jednego, wymieniania jest przestrzeń adresowa, context switch i leci kolejne klasyk. Fajne bo pozwala na zarządzaniewieloma zadaniami bez całkowitego zatrzymania któregoś z nich.

*Procedury wielobieżne (ang. reentrant)* - To procedura, której wykonanie może zostać przerwana, sygnałem lub wywołaniem innej funkcji w jej ciele, wtedy wywołujemy ją jeszcze raz, to pierwsze wywołanie musi poczekać aż drugie się zakończy, a jak 2 się zakończy, to wracając do pierwszego możemy je dalej bezpiecznie kontynuować

Generalnie uzyskuje się to przez używania jedynie parametrów i lokalnych zmiennych leżących na stosie, nie lockuje żadnych globalnym zasobów podczas wykonania. Nie może modyfikować swojego kodu, wołać innych procedur NIEwielobieżnych (no całkiem logiczne).

*Procedura wielowątkowo-bezpieczna (ang. MT-safe)* - procedura, która może być bezpiecznie wołana z kilku wątków jednocześnie jednocześnie gwarantując brak race conditions

Przykład procedury wielobieżnej (reentrant), ale NIE wielowątkowo-bezpiecznej

Procedura wielowątkowo-bezpieczna, ale nie wielobieżna (reentrant)

```clike=
# include <pthread.h>

int increment_counter ()
{
  static int counter = 0;
  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

  // only allow one thread to increment at a time
  pthread_mutex_lock(&mutex);

  ++counter;

  // store value before any other threads increment it further
  int result = counter;

  pthread_mutex_unlock(&mutex);

  return result;
}
```
W powyższej procedurze `increment_counter` może być wołany przez różne wątki bez problemu ponieważ mutex jest używany do sychronizowania wszystkich dostępów to dzielonej zmiennej `counter`. Ale jeśli funkcja zostanie użyta przez reentrant interrupt handler i drugie przerwanie dotrze gdy mutex jest zablokowany, druga procedura zawiesi się na zawsze, będzie deadlock.

Procedura wielobieżna, ale nie wielo-wątkowa


```clike=
int t;

void swap(int *x, int *y)
{
        int s;

        s = t;  // save global variable
        t = *x;
        *x = *y;
        // hardware interrupt might invoke isr() here!
        *y = t;
        t = s;  // restore global variable
}

void isr()
{
        int x = 1, y = 2;
        swap(&x, &y);
}
```

Reentrant:
 1) swap1(1,2)
 2) t = 1
 3) swap2(3,4)
 4) t = 3
 5) swap2 przywraca t = 1
 6) wracamy do swap1, który widzi t = 1 (czyli git)

Thread A         Thread B
 1) int s;        int s;
 2) s = 100;      s = 100;
 3) t = 5;        no operation;
 4) no operation; t = 20;  // t is global so Thread A also sees the value as t = 20
 5) x = 10;       x = 30;
 6) y = 20;       y = 20;  // Thread A exchange is wrong, Thread B exchange is OK  


*Kiedy w jednowątkowym procesie uniksowym może wystąpić współbieżność?*

Nie wiem ale czy chodzi tutaj o event processing? - ślisko ale tak, bo te nasze wewnętrzne joby są współbieżne względem siebie więc git, ale z punktu widzenia procesora dalej to jest jeden proces
Obsługa sygnałów


### Zadanie 2
![](https://i.imgur.com/NxWKInV.png)

*Zakleszczenie (ang. deadlock)* -  sytuacja w której dwa lub więcej wątków blokuje się na stałe, ponieważ każdy z nich chce uzyskać dostęp do zasobu, który jest już zajęty przez drugi wątek.

Np:

```clike=
//thread A
if(lock(x))
    if(lock(y))
     //do sth

//thread B
if(lock(y))
    if(lock(x))
     //do sth
    
```

Thread A
 1) lock(x);      
 2) czekaj dopóki zasób y zostanie zwolniony     

Thread A
 1) lock(y);      
 2) czekaj dopóki zasób x zostanie zwolniony     

*Uwięzenie (ang. livelock)* - sytuacja w której dwa lub więcej wątków konkurują o dostęp do tego samego zasobu, lecz ściągają swoje blokady, żeby uniknać deadlock'a i pozwolić uzyskać dostęp do tego zasobu innym zasobom, i to też może ciągnać się w nieskończoność - dobrym przykładem są dwie osoby na korytarzu, które aby się minać wybierają cały czas stronę, w którą się przesunąć, i tak cały czas przesuwają się w lewo, potem w prawo, potem w lewo itd.

```clike=
//thread A
if(lock(x))
    while(y is locked) {
     x unlock
     wait
     x lock
}

//thread B
if(lock(y))
    while(x is locked) {
     y unlock
     wait
     y lock
}
    
```

*Głodzenie (ang. starvation)* - sytuacja w której scheduler priorytetuje jakąś grupę wątków A, która blokuje zasób X przez co grupa wątków B nie dostanie możliwości dostępu do zasobu X i będzie głodzona.

### Zadanie 3
![](https://i.imgur.com/noXs91I.png)

*Sytuacja wyścigu (ang. race condition)* - występuje wtedu, gdy dwa lub więcej proceów jednocześnie czytają/zapisują współdzielone dane, a rezultat zależy od tego, jaki był przeplot wykonania procesów.

MIN:
1. tally = 0

2. tally = 0
   wykonuje 49 iteracji zapisując tally = 49
   
2. wykonuje 1 iteracje zapisujac tally = 1
   
2. wykonujac 50 iteracje pobiera z rejestru        tally = 1

1. wykonuje wszystkie iteracje i zapisuje tally    = 50

2. drugi ma pobrane tally = 1, dodaje 2 i          zapisuje tally = 2


MAX:
wykonuja sie naprzemienne
proces 1. ustawia tally = 0
proces 2. ustawia tally = 0
proces 1. pobiera tally = 0, dodaje 1 i zapisuje           tally = 1
proces 2. pobiera tally = 1, dodaje 1 i zapisuje           tally = 2
proces 1. pobiera tally = 2, dodaje 1 i zapisuje 
          tally = 3
itd itd ...

### Zadanie 4
![](https://i.imgur.com/ks4537Q.png)

fork    - pthread_create
![](https://i.imgur.com/J5hC0D0.png)

thread - identyfikator wątku
attr - atrybuty wątku, PTHREAD_CREATE_JOINABLE/DETACHED, rozmiar i adres stosu itd ...
start_routine - funkcja wykonywana w wątku
arg - argumenty przekazywane do funkcji (wskaźnik na strukturę danych)

exit    - pthread_exit
![](https://i.imgur.com/Qo4qHdn.png)
kończy wątek z return value retval

waitpid - pthread_join
![](https://i.imgur.com/Dg6nxgA.png)
czeka na thread aż się zakończy i go grzebie (zwalnia jego zasoby - chyba wlasny stos maja watki). Jeśli ten tred już się zakończy, to pthread_join wraca od razu. Thread musi być joinable. Jeśli thread zwrócił jakąś wartość to jest zwracana w retval, jeśli został anulowany to znajdzie się tam wartosć PTHREAD_CANCELED

atexit  - pthread_cleanup_push
![](https://i.imgur.com/8BfJR6z.png)
![](https://i.imgur.com/U2hFU27.png)
dodanie na górę stosu wątku procedurę routine:

Program czyszczący jest ściągany ze stosu i  wykonywany w następujących okolicznościach:

1. Gdy wątek jest anulowany (wszystkie handlery czyszące są ściągane ze stosu i wykonywane w odwrotnej kolejności do ich wrzucania)
2. Gdy wątek jest zakończony przez pthread_exit (dzieje się to samo co wyżej)
3. Kiedy zostanie zawołane pthread_cleanup_pop z niezerowym argumentem zostanie wykonana top-most procedura

abort   - pthread_cancel
![](https://i.imgur.com/nsmVCFw.png)
wysyła request o anulowanie do wątku thread, wątek zachowa się w zależności od jego cancelability state i type:

state - może być wyłączony, przez co żądanie anulowania zostanie zakolejkowane i wywołane gdy wątek ustawi swój stan na enabled

type:
jeśli jest asonchronous - anulowanie dzieje się od razu
jeśli jest deffered - dzieje się, gdy wątek zawoła jedną z funkcji zdefiniowanych jako cancellation point

*wątki złączalne (ang. joinable)* - domyślny rodzaj działania wątków, są przywiązane do procesu i musimy wykonać na nich pthread_join, żeby je pogrzebać, caller po powrocie w wywołania pthread_join ma gwarancje, ze watek się zakończył i może wybrać jakie prace "sprzątające" chce wykonać. (taki kinda waitpid?) jeśli caller sam nie posprząta to jest sprzątane na koniec programu

*wątki odczepione (ang. detached)* - wątki które po zakończeniu działania same zwalniają wykorzystane przez siebie zasoby. wywołanie exit skutkuje posrzątaniem stosu po sobie


