problema dei lettori e degli scrittori
Transcript
problema dei lettori e degli scrittori
Lettori/Scrittori Il problema Una struttura dati è condivisa da un insieme di thread, che appartengono a una delle due seguenti categorie: • Thread lettori: accedono alla struttura dati esclusivamente per leggere, senza modificare i dati; • Thread scrittori: accedono alla struttura dati senza restrizioni, con la possibilità di modificare i dati. Per evitare interferenze, sono imposti seguenti vincoli: • i thread scrittori accedono alla struttura dati in mutua esclusione, rispetto agli altri scrittori e ai lettori; • i thread lettori accedono alla struttura dati in mutua esclusione rispetto agli scrittori, ma senza vincolo di mutua esclusione rispetto agli altri lettori (in altre parole, più lettori possono utilizzare la struttura dati concorrentemente). Il problema Il problema viene risolto con una politica che consente l’accesso alternativamente a uno scrittore e a un insieme di lettori, ed evita l’attesa indefinita per gli scrittori. Precisamente, per le richieste valgono le seguenti clausole: 1. Quando la struttura dati non è utilizzata da nessun processo: • accede il primo processo (lettore o scrittore) che ne fa richiesta; 2. Quando la struttura dati è utilizzata da uno scrittore, oppure da uno o più lettori: • se un lettore richiede l’accesso e la struttura dati è utilizzata da uno scrittore, il lettore richiedente viene sospeso; • se un lettore richiede l’accesso e la struttura dati è utilizzata da uno o più lettori, il lettore ottiene l’accesso a condizione che non vi siano scrittori in attesa; • se un lettore richiede l’accesso, la struttura dati è utilizzata da uno o più lettori e vi è almeno uno scrittore in attesa di accedere, il lettore richiedente viene sospeso (questa clausola evita l’attesa indefinita per gli scrittori); • se uno scrittore richiede l’accesso e la struttura dati è utilizzata da uno scrittore oppure da uno o più lettori, lo scrittore si sospende. Il problema Per i rilasci valgono le seguenti clausole: 3. quando uno scrittore rilascia la struttura dati: • se esistono lettori in attesa, tutti questi lettori sono riattivati e ottengono l’accesso; • se non esistono lettori in attesa ma esiste almeno uno scrittore in attesa, il primo di questi scrittori ottiene l’accesso; • se non esistono lettori o scrittori in attesa, si torna al caso 1). 4. quando un lettore rilascia la struttura dati: • se altri lettori stanno ancora utilizzando la struttura dati, continua l’accesso in lettura da parte di questi thread; • se non vi sono altri lettori che utilizzano la struttura dati ed esiste almeno uno scrittore in attesa, il primo di questi scrittori ottiene l’accesso; • altrimenti si torna al caso 1). Il problema Per la soluzione del problema, si utilizzano i seguenti dati condivisi da tutti i thread: • activeReaders : intero non negativo; valore iniziale 0 • waitingReaders : intero non negativo; valore iniziale 0 • activeWriters : intero non negativo; valore iniziale 0 • waitingWriters : intero non negativo; valore iniziale 0 e le seguenti variabili: • Lock mutex: per la mutua esclusione; • Cond readGo: variabile di condizione utilizzata per la sospensione dei lettori; • Cond writeGo : variabile di condizione utilizzata per la sospensione degli scrittori; Lettore … While (true) { RWLock::startRead(); <accede in lettura alla struttura condivisa> RWLock::doneRead(); <usa i dati letti> } … Scrittore … While (true) { <prepara dati da scrivere> RWLock::startWrite(); <accede in scrittura alla struttura condivisa> RWLock::doneWrite(); } … Lettore – startRead(), doneRead() void RWLock::startRead() { ……………………………………. waitingReaders++; while (activeWriters > 0 || waitingWriters > 0) { ……………………………………. } waitingReaders --; activeReaders++; ……………………………………. } void RWLock::doneRead() { ……………………………………. activeReaders--; if (activeReaders ==0 && waitingWriters > 0) { ……………………………………. } ……………………………………. } Scrittore – startWrite(), doneWrite() void RWLock::startRead() { ……………………………………. waitingWriters++; while (activeWriters > 0 || activeReaders > 0) { ……………………………………. } waitingWriters --; activeWriters++; ……………………………………. } void RWLock::doneWrite() { ……………………………………. activeWriters--; if (waitingWriters > 0) { ……………………………………. } else readGo.Broadcast(&mutex); ……………………………………. } Lettore – startRead() void RWLock::startRead() { mutex.Acquire(); waitingReaders++; while (activeWriters > 0 || waitingWriters > 0) { readGo.Wait(&mutex); } waitingReaders --; activeReaders++; mutex.Release(); } Lettore – doneRead() void RWLock::doneRead() { mutex.Acquire(); activeReaders--; if (activeReaders ==0 && waitingWriters > 0) { writeGo.Signal(&mutex); } mutex.Release(); } Scrittore – startWrite() void RWLock::startRead() { mutex.Acquire(); waitingWriters++; while (activeWriters > 0 || activeReaders > 0) { writeGo.Wait(&mutex); } waitingWriters --; activeWriters++; mutex.Release(); } Scrittore – doneWrite() void RWLock::doneWrite() { mutex.Acquire(); activeWriters--; assert(activeWriters == 0); if (waitingWriters > 0) { writeGo.Signal(&mutex); } else readGo.Broadcast(&mutex); mutex.Release(); }