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();
}