Sushi bar problem The Little Book of Semaphores by Allen B. Downey http://greenteapress.com/semaphores/ 1
Sushi bar problem Immaginiamo di avere un sushi bar con 5 sedie. Se un cliente arriva e c'è una sedia vuota si può sedere immediatamente. Se le 5 sedie sono occupate, allora i commmensali stanno mangiando assieme, e per entrare bisogna attendere che la cena sia finita prima di sedersi (si alzano tutti più o meno tutti assieme). In altri termini, le sedie devono tornare ad essere tutte libere Scrivere il comportamento del processo customer per entrare e uscire dal sushi bar. 2
Sushi bar problem // num proc seduti e in attesa int eating = 0, waiting = 0; Semaphore mutex = Semaphore(1); // sem per far attendere i processi mentre si mangia Semaphore block = new Semaphore(0); boolean must_wait = false; // bar pieno 3
Sushi bar problem: soluzione errata block.p(); // riprendo la m.e. waiting = 1; must_wait = (eating == 5); if (eating == 0) { n = min(5, waiting); for i=1:n block.v(); must_wait = false; 4
Sushi bar problem: soluzione errata block.p(); // riprendo la m.e. waiting = 1; must_wait = (eating == 5); if (eating == 0) { n = min(5, waiting); for i=1:n block.v(); must_wait = false; 5
Sushi bar problem: soluzione errata block.p(); // riprendo la m.e. waiting = 1; must_wait = (eating == 5); if (eating == 0) { n = min(5, waiting); for i=1:n block.v(); must_wait = false; Se arrivo e il bar è pieno, lascio la m.e. e aspetto che altri altri escano. Quando l'ultimo esce, segnala facendo block.v() Svegliando alcuni in attesa e ponendo a false must wait. 6
Sushi bar problem: soluzione errata block.p(); // riprendo la m.e. waiting = 1; must_wait = (eating == 5); if (eating == 0) { n = min(5, waiting); for i=1:n block.v(); must_wait = false; Ma quando il cliente si sveglia, deve attendere di riprendere la m.e. e nel farlo compete con altri che arrivano. Se i nuovi arrivano a prendere la mutex prima, possono prendersi le sedie prima di lui. 7
Sushi bar problem: soluzione errata block.p(); // riprendo la m.e. waiting = 1; must_wait = (eating == 5); Non if è solo (eating un problema == 0) di ingiustizia; { può capitare n = che min(5, più di 5 processi waiting); passino Se 5 processi for sono i=1:n già entrati, il processo Che prende la block.v(); m.e. qui entra per mangiare anche lui must_wait = false; 8
Sushi bar problem: soluzione #1 Il problema proveniva dall'accesso alla m.e. Per modificare le variabili eating e waiting Demandiamo al processo che esce di modificare i valori di eating e waiting 9
Sushi bar problem: soluzione #1 block.p(); else { must_wait=(eating==5); if (eating == 0) { n = min(5, waiting); waiting = n; eating += n; must_wait=(eating==5); for i=1:n block.v(); 10
Sushi bar problem: soluzione #1 block.p(); else Quando { l'ultimo lascia la m.e., la var eating è stata già modificata, per cui i nuovi arrivati si bloccano, visto che lo must_wait=(eating==5); stato è già stato aggiornato if (eating == 0) { n = min(5, waiting); waiting = n; eating += n; must_wait=(eating==5); for i=1:n block.v(); 11
Sushi bar problem: soluzione #2 Usiamo il passaggio del testimone 12
Sushi bar problem: soluzione #2 block.p(); // m.e. passata waiting = 1; must_wait = (eating == 5); if (waiting &&! must_wait) block.v(); // pass m.e. else if (eating == 0) must_wait = false; if (waiting &&!must_wait) block.v(); // pass m.e. else 13
Sushi bar problem: soluzione #2 block.p(); // m.e. passata waiting = 1; must_wait = (eating == 5); if (waiting &&! must_wait) block.v(); // pass m.e. else if (eating == 0) must_wait = false; if (waiting &&!must_wait) Se voglio block.v(); entrare e eating // < pass 5 passo. m.e. else Il quinto setta must_wait 14
Sushi bar problem: soluzione #2 block.p(); // m.e. passata waiting = 1; must_wait = (eating == 5); if (waiting &&! must_wait) Se must_wait è vera, i clienti si bloccano block.v(); // pass m.e. finché l'ultimo la setta a false e chiama la V() su block La block.v() passa il testimone al primo processo bloccato else if (eating == 0) must_wait = false; if (waiting &&!must_wait) block.v(); // pass m.e. else 15
Sushi bar problem: soluzione #2 block.p(); // m.e. passata waiting = 1; must_wait = (eating == 5); if (waiting &&! must_wait) block.v(); // pass m.e. else if (eating == 0) must_wait = false; Il processo if (waiting svegliato si && segna!must_wait) come eating, block.v(); e verifica se può // svegliare pass m.e. altri processi bloccati su block In else tal caso gli passa la mutex Si va avanti finché non finiscono processi in attesa o raggiungo i 5 clienti, al che l'ultimo rilascia la mutex 16
Sushi bar problem: soluzione #1 coi monitor procedure entry entra() { block.wait(); else { must_wait=(eating==5); procedure entry esci(){ if (eating == 0) { n = min(5, waiting); waiting = n; eating += n; must_wait=(eating==5); for i=1:n block.signal(); 17
Sushi bar problem: soluzione message passing I processi variano non si conoscono serve un processo server A questo punto il problema si risolve banalmente con una sincronizzazione via messaggio Il client manda msg al server e aspetta risposta Quando esce informa il server Il server riceve msg e mette chi aspetta in coda o fa entrare se c'è posto Quando la sala si svuota ne sveglia 5 (se ci sono) 18