184 lines
5.1 KiB
Markdown
184 lines
5.1 KiB
Markdown
|
# Semafori concorrenti - HHO
|
||
|
*(scrivi il resto)*
|
||
|
## No deadlock
|
||
|
|
||
|
Per assurdo, supponiamo deadlock al tempo T: i semafori si bloccano su P (idrogeno su P(sH), ossigeno su uno dei P(sO))
|
||
|
|
||
|
* Invarianti semaforici
|
||
|
```
|
||
|
val(sH,T) = 0
|
||
|
=> NP(sO, T) = NV(s0,T) // nessuna P eseguita con successo, il valore di sH e' 0 perche' il processo e' bloccato
|
||
|
|
||
|
val(sO,T) = 0
|
||
|
=> NP(sH, T) = NV(sH, T) + 2
|
||
|
```
|
||
|
|
||
|
* utilizziamo gli invarianti topologici
|
||
|
```
|
||
|
NP (sH, T) = NV (sO, T)
|
||
|
=> 0 <= NP(sO,T) - NV (sH,T) <= 1
|
||
|
```
|
||
|
|
||
|
* Cerchiamo un assurdo:
|
||
|
```
|
||
|
NV (sH, T) + 2 = NP (sH, T) = NV (sO, T) <= NV (sH,T) + 1
|
||
|
```
|
||
|
* Il risultato non e' ammissibile (2<1) quindi non e' possibile ottenere deadlock dalla soluzione presentata.
|
||
|
|
||
|
# Uso di Semafori Privati
|
||
|
|
||
|
Semafori (binari/contatori) di **proprieta' di uno o piu' processi**.
|
||
|
I proprietari sono gli unici a poter eseguire P sul suddetto semaforo, ma **non ci sono restrizioni sull'uso di V**.
|
||
|
|
||
|
## Utilizzi
|
||
|
|
||
|
* Svegliare un determinato processo, per rendere la gestione di una coda di processi indipendente dall'implementazione del semaforo (kernel space). In questo modo posso stabilire una gerarchia di prorita' tra processi.
|
||
|
|
||
|
### Vantaggi
|
||
|
|
||
|
Precisione nella gestione di pool di processi.
|
||
|
|
||
|
### Svantaggi
|
||
|
|
||
|
Complessita' aggiunta all'implementazione: il programma deve mantenere piu' semafori (anche a livello di kernel: i semafori privati possono essere implementati **al di fuori** di una coda). Il caso piu' comune e' la necessita' di dover mantenere un semaforo per ogni processo in coda, invece che uno solo (e una coda).
|
||
|
|
||
|
## Schemi di gestione
|
||
|
|
||
|
### Schema 1
|
||
|
|
||
|
Contesto:
|
||
|
```
|
||
|
< struttura dati gestore >
|
||
|
semaphore mutex;
|
||
|
semaphore priv[n] = {0}; // array di semafori privati, ognuno dedicato a un processo (n processi)
|
||
|
```
|
||
|
|
||
|
#### Procedura di acquisizione
|
||
|
```
|
||
|
public int acquisisci (int p) {
|
||
|
// simile ai semafori condizionali, anche qui dovremo testare l'ottenibilita' di una risorsa
|
||
|
int j; // risorsa da allocare
|
||
|
P (mutex);
|
||
|
if ( ! Cp) { // Cp e' la condizione per il processo p
|
||
|
< registrare sospensione del processo p >
|
||
|
V (mutex);
|
||
|
P (priv[p]);
|
||
|
< registro che il processo p non e' piu' sospeso >
|
||
|
}
|
||
|
< alloco risorsa j >
|
||
|
V (mutex);
|
||
|
return j;
|
||
|
}
|
||
|
```
|
||
|
#### Procedura di rilascio
|
||
|
```
|
||
|
public void rilascio (int j) {
|
||
|
int p;
|
||
|
P (mutex);
|
||
|
< registro rilascio risorsa j >
|
||
|
if ( < esiste almeno 1 processo sospeso > ) {
|
||
|
< scelgo il processo p con massima priorita' >
|
||
|
V (priv[p]);
|
||
|
} else {
|
||
|
V (mutex);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
### Esempio: allocazione di pool di risorse
|
||
|
|
||
|
```
|
||
|
int avail = M;
|
||
|
bool libero[M] = {true};
|
||
|
bool sospeso[n] = {false};
|
||
|
int cnts = 0; // conta i sospesi
|
||
|
semaphore mutex;
|
||
|
semaphore priv[n] = {0}; // array di semafori privati, ognuno dedicato a un processo (n processi)
|
||
|
```
|
||
|
#### Procedura di acquisizione
|
||
|
```
|
||
|
public int acquisisci (int p) {
|
||
|
int j; // risorsa da allocare
|
||
|
P (mutex);
|
||
|
if ( avail == 0) {
|
||
|
sospeso[p] = true;
|
||
|
cnts++;
|
||
|
V (mutex);
|
||
|
P (priv[p]);
|
||
|
sospeso[p] = false;
|
||
|
cnts--;
|
||
|
}
|
||
|
avail--;
|
||
|
while (libero[j]) j++;
|
||
|
libero[i] = false;
|
||
|
V (mutex);
|
||
|
return j;
|
||
|
}
|
||
|
```
|
||
|
#### Procedura di rilascio
|
||
|
```
|
||
|
public void rilascio (int j) {
|
||
|
int p;
|
||
|
P (mutex);
|
||
|
avail++;
|
||
|
libero[j] = true;
|
||
|
if ( cnts > 0 ) {
|
||
|
p = maxpriority (sospeso); // ottengo il processo con priorita' massima
|
||
|
V (priv[p]);
|
||
|
} else {
|
||
|
V (mutex);
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
### Schema 2
|
||
|
|
||
|
Siccome e' complesso dal punto di vista della programmazione strutturata (alto livello), e' stato proposto un secondo schema.
|
||
|
|
||
|
#### Procedura di acquisizione
|
||
|
```
|
||
|
public void acquisizione (int p) {
|
||
|
P (mutex);
|
||
|
if (Cp) {
|
||
|
< alloca risorsa >
|
||
|
V (priv[p]);
|
||
|
} else {
|
||
|
< registro sospensione processo p>
|
||
|
}
|
||
|
V (mutex);
|
||
|
P (priv[p]); // a seconda del valore di Cp, questa P e' sospensiva (!Cp) o vanificata dalla V (Cp)
|
||
|
}
|
||
|
```
|
||
|
*nota: la risorsa in questo caso e' garantita dal processo che rilascia, perche' se Cp non e' verificata, questa procedura non alloca nulla*
|
||
|
|
||
|
#### Procedura di rilascio
|
||
|
```
|
||
|
public void rilascio (int j) {
|
||
|
int p;
|
||
|
P (mutex);
|
||
|
< registro rilascio risorsa j >
|
||
|
if ( < esiste almeno 1 processo sospeso > ) {
|
||
|
< scelgo il processo p con massima priorita' >
|
||
|
< alloco risorsa >
|
||
|
< registro che p non e' sospeso >
|
||
|
V (priv[p]);
|
||
|
}
|
||
|
V (mutex);
|
||
|
}
|
||
|
```
|
||
|
#### Pro e contro della soluzione 2
|
||
|
|
||
|
* Un problema della soluzione 2 e' che e' limitato a 1 dato libero per volta (se i processi consumatori hanno bisogno di piu' di un "dato" (risorsa), non ho modo di sapere quanti ne sto rilasciando), mentre la soluzione 1 implementata con un *while* risolve questo problema.
|
||
|
|
||
|
* Siccome il processo rilasciante si occupa anche di allocare le risorse, non si puo' effettuare il passaggio di parametri. Questo caso e' ovviato dall'utilizzo di un array condiviso *allocazione* che fornisce l'indice della risorsa che e' stata allocata.
|
||
|
|
||
|
# Problema dell'accesso unico (senso unico alternato) - Readers & Writers
|
||
|
|
||
|
## Precedenza agli scrittori
|
||
|
|
||
|
L'implementazione con precedenza agli scrittori permette di bloccare i readers se un writer e' nella SC, ma anche se un writer e' in attesa.
|
||
|
|
||
|
## Soluzione bilanciata
|
||
|
|
||
|
Utilizzando dei semafori privati, e' possibile associare un semaforo privato a lettori e scrittori, ottenendo un accesso limitato degli scrittori alla SC, e quindi ottenendo una soluzione equilibrata.
|
||
|
|
||
|
|