Zibaldone

From Sistemi Operativi
Revision as of 19:37, 13 November 2016 by Renzo (talk | contribs) (→‎RW2bis)
Jump to navigation Jump to search

RW errato

Codice ERRATO dei lettori scrittori che dovrebbe non soffrire di problemi di starvation... Esercizio: trovare gli errori.

#include<stdio.h>
#include<stdint.h>
#include<pthread.h>
#include<semaphore.h>

#define NREADER 3
#define NWRITER 3
semaphore mutex;
semaphore ok2read;
semaphore ok2write;

int nr=0;
int nw=0;
int wr=0;
int ww=0;
int w_last;

// (nw == 0 && nr == 0) || (nr > 0 && nw == 0) || nw == 1
// (nw == 0 && nr >= 0) || nw == 1

// this "baton" function has been left for reference only.
// code to implement "passing the baton" has been copied at the end of
// each ({start}|{end})({read}|{write}) function and reduced.
void baton(void) {
        if (nw == 0 && nr == 0 && ww > 0)
                semaphore_V(ok2write);
        else if (nw == 0 && wr > 0 )
                semaphore_V(ok2read);
        else
                semaphore_V(mutex);
}

void startread(void) {
// <await nw == 0 -> nr++>
        semaphore_P(mutex);
        if (nw > 0 && ww == 0) {
                wr++;
                semaphore_V(mutex);
                semaphore_P(ok2read);
                wr--;
        }
        nr++;
        w_last=0;
        printf("NR %d - NW %d - WR %d - WW %d \n", nr, nw, wr, ww);
        if (wr > 0 )
                semaphore_V(ok2read);
        else
                semaphore_V(mutex);
}

void endread(void) {
// <nr-->
        semaphore_P(mutex);
        nr--;
        printf("NR %d - NW %d - WR %d - WW %d \n", nr, nw, wr, ww);
        if (nr == 0 && ww > 0)
                semaphore_V(ok2write);
        else
                semaphore_V(mutex);
}

void startwrite(void) {
// <await nw == 0 && nr == 0 -> nw++>
        semaphore_P(mutex);
        if (nw > 0 || nr > 0) {
                ww++;
                semaphore_V(mutex);
                semaphore_P(ok2write);
                ww--;
        }
        nw++;
        w_last=1;
        printf("NR %d - NW %d - WR %d - WW %d \n", nr, nw, wr, ww);
        semaphore_V(mutex);
}

void endwrite(void) {
// <nw-->
        semaphore_P(mutex);
        nw--;
        printf("NR %d - NW %d - WR %d - WW %d \n", nr, nw, wr, ww);
        if (wr > 0 && (ww == 0 || w_last))
                semaphore_V(ok2read);
        else if (ww > 0 && (wr == 0 || !w_last))
                semaphore_V(ok2write);
        else
                semaphore_V(mutex);
}

void *reader(void *arg) {
        int i = (uintptr_t)arg;
        while (1) {
                //other code
                usleep(random() % 200000);
                startread();
                //read
                usleep(random() % 200000);
                endread();
        }
}

void *writer(void *arg) {
        int i = (uintptr_t)arg;
        while (1) {
                //other code
                usleep(random() % 200000);
                startwrite();
                //write
                usleep(random() % 200000);
                endwrite();
        }
}


//printf("philo thinking: %d\n",i);
/*while*/

int main(int argc, char *argv[]) {
        int i;
        pthread_t t;
        srandom(time(NULL));
        mutex=semaphore_create(1);
        ok2read=semaphore_create(0);
        ok2write=semaphore_create(0);
        for (i=0; i<NREADER; i++)
                pthread_create(&t, NULL, reader, (void *)(uintptr_t) i);
        for (i=0; i<NWRITER; i++)
                pthread_create(&t, NULL, writer, (void *)(uintptr_t) i);
        while(1)
                pause();
}

RW di FedericoB

Propongo la seguente soluzione. Mi sembra che funzioni ma devo ancora capire perchè e documentarla bene. Ho provato prima a cercare il bug ma non ci sono riuscito. Ho quindi modificato il codice secondo ciò che mi sembrava sensato in base alle condizioni del problema. Ne possiamo parlare in aula oggi. --FedericoB (talk) 12:48, 11 November 2016 (CET) Ho notato che l'errore non si manifesta più eliminando il controllo che ci siano scrittori in attesa quando un lettore vuole iniziare a scrivere. Non capisco come questo possa essere collegato al bug. --FedericoB (talk) 15:10, 11 November 2016 (CET)

FedericoB, questa soluzione è quella con priorità ai lettori, no? Se continuano ad arrivare lettori numberOfReaders non sarà mai zero e quindi gli scrittori non scriveranno mai. Renzo (talk) 10:34, 12 November 2016 (CET)

SFIDA: ho trovato il modo di togliere la starvation aggiungendo 4 token (parole chiave, nomi di variabili, operatori, costanti) a questa soluzione di FedericoB. Chi trova la soluzione? Renzo (talk) 10:43, 12 November 2016 (CET) Ah! ho appena trovato una soluzione che prevede 2 soli token in più! Renzo (talk) 10:47, 12 November 2016 (CET)

#include<stdio.h>
#include<stdint.h>
#include<pthread.h>
#include<semaphore.h>

#define NUMBER_OF_READERS 3
#define NUMBER_OF_WRITERS 3
semaphore mutex;
semaphore ok2read;
semaphore ok2write;

int numberOfReaders=0;
int numberOfWriters=0;
int waitingReaders=0;
int waitingWriters=0;

// (nw == 0 && nr == 0) || (nr > 0 && nw == 0) || nw == 1
// (nw == 0 && nr >= 0) || nw == 1

void startread(void) {
// <await nw == 0 -> nr++>
    semaphore_P(mutex);
    if (numberOfWriters > 0) {
        waitingReaders++;
        semaphore_V(mutex);
        semaphore_P(ok2read);
        waitingReaders--;
    }
    numberOfReaders++;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
    if (waitingReaders > 0 )
        semaphore_V(ok2read);
    else
        semaphore_V(mutex);
}

void endread(void) {
// <nr-->
    semaphore_P(mutex);
    numberOfReaders--;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
    if (numberOfReaders == 0 && waitingWriters > 0)
        semaphore_V(ok2write);
    else
        semaphore_V(mutex);
}

void startwrite(void) {
// <await nw == 0 && nr == 0 -> nw++>
    semaphore_P(mutex);
    if (numberOfWriters > 0 || numberOfReaders > 0) {
        waitingWriters++;
        semaphore_V(mutex);
        semaphore_P(ok2write);
        waitingWriters--;
    }
    numberOfWriters++;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
    semaphore_V(mutex);
}

void endwrite(void) {
// <nw-->
    semaphore_P(mutex);
    numberOfWriters--;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
    if (waitingReaders > 0)
        semaphore_V(ok2read);
    else if (waitingWriters > 0)
        semaphore_V(ok2write);
    else
        semaphore_V(mutex);
}

void *reader(void *arg) {
    int i = (uintptr_t)arg;
    while (1) {
        //other code
        usleep(random() % 200000);
        startread();
        //read
        usleep(random() % 200000);
        endread();
    }
}

void *writer(void *arg) {
    int i = (uintptr_t)arg;
    while (1) {
        //other code
        usleep(random() % 200000);
        startwrite();
        //write
        usleep(random() % 200000);
        endwrite();
    }
}


//printf("philo thinking: %d\n",i);
/*while*/

int main(int argc, char *argv[]) {
    int i;
    pthread_t t;
    srandom(time(NULL));
    mutex=semaphore_create(1);
    ok2read=semaphore_create(0);
    ok2write=semaphore_create(0);
    for (i=0; i<NUMBER_OF_READERS; i++)
        pthread_create(&t, NULL, reader, (void *)(uintptr_t) i);
    for (i=0; i<NUMBER_OF_WRITERS; i++)
        pthread_create(&t, NULL, writer, (void *)(uintptr_t) i);
    while(1)
        pause();
}

RW2

Buongiorno, guardando il codice visto a lezione mi sembra che cambiando la condizione del primo if nella startread() da "if (nw > 0 && ww == 0)" a "if (nw > 0 || ww > 0)" la situazione migliori. In particolare con l'and tra quelle due condizioni si aveva che non veniva fatta la P sull'ok2read anche quando si aveva nw>0 (con ww!=0), cosa che invece dovrebbe fare. Lasciando il resto del codice uguale mi sembra che faccia quello che deve fare.. .

Matteo.pincherle: Perché non modifichi in programma di FedericoB, lo provi e pubblichi qui la patch? Renzo (talk) 10:42, 13 November 2016 (CET)

Perchè quel AND permetteva di avere 2 scrittori?
Permetteva in primis di avere dei lettori in contemporanea a uno scrittore. In quanto se succedeva che un lettore volesse entrare mentre non c'erano degli scrittori in attesa ma scrittori in scrittura, veniva saltato il blocco che mandava il lettore in attesa e risultava un lettore in contemporanea a uno scrittore.
Questo lettore poi poteva finire di leggere prima che lo scrittore in contemporanea a lui finisse di scrivere.
Il lettore in uscita se non c'erano altri lettori con lui e non c'erano scrittori in attesa dava il permesso per far accedere un altro scrittore.
A questo punto un altro scrittore che avesse voluto entrare poteva entrare, con il risultato di avere 2 scrittori in contemporanea. --FedericoB (talk) 19:25, 13 November 2016 (CET)

Patch

Così, se non sbaglio, quando c'è almeno uno scrittore in attesa non lascia entrare altri lettori. Fa esaurire la lettura dei presenti e poi lascia scrivere lo scrittore.

#include<stdio.h>
#include<stdint.h>
#include<pthread.h>
#include<semaphore.h>

#define NUMBER_OF_READERS 3
#define NUMBER_OF_WRITERS 3
semaphore mutex;
semaphore ok2read;
semaphore ok2write;

int numberOfReaders=0;
int numberOfWriters=0;
int waitingReaders=0;
int waitingWriters=0;
int w_last;

// (nw == 0 && nr == 0) || (nr > 0 && nw == 0) || nw == 1
// (nw == 0 && nr >= 0) || nw == 1

void startread(void) {
    // <await nw == 0 -> nr++>
    semaphore_P(mutex);
    if (numberOfWriters > 0 || waitingWriters>0) {
        waitingReaders++;
        semaphore_V(mutex);
        semaphore_P(ok2read);
        waitingReaders--;
    }
    numberOfReaders++;
    w_last=0;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
    if (waitingReaders > 0 )
        semaphore_V(ok2read);
    else
        semaphore_V(mutex);
}

void endread(void) {
    // <nr-->
    semaphore_P(mutex);
    numberOfReaders--;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
    if (numberOfReaders == 0 && waitingWriters > 0)
        semaphore_V(ok2write);
    else
        semaphore_V(mutex);
}

void startwrite(void) {
    // <await nw == 0 && nr == 0 -> nw++>
    semaphore_P(mutex);
    if (numberOfWriters > 0 || numberOfReaders > 0) {
        waitingWriters++;
        semaphore_V(mutex);
        semaphore_P(ok2write);
        waitingWriters--;
    }
    numberOfWriters++;
    w_last=1;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
    semaphore_V(mutex);
}

void endwrite(void) {
    // <nw-->
    semaphore_P(mutex);
    numberOfWriters--;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
    if (waitingReaders > 0 && (waitingWriters==0 || w_last))
        semaphore_V(ok2read);
    else if (waitingWriters > 0 && (waitingReaders==0 || !w_last))
        semaphore_V(ok2write);
    else
        semaphore_V(mutex);
}

void *reader(void *arg) {
    int i = (uintptr_t)arg;
    while (1) {
        //other code
        usleep(random() % 200000);
        startread();
        //read
        usleep(random() % 200000);
        endread();
    }
}

void *writer(void *arg) {
    int i = (uintptr_t)arg;
    while (1) {
        //other code
        usleep(random() % 200000);
        startwrite();
        //write
        usleep(random() % 200000);
        endwrite();
    }
}

int main(int argc, char *argv[]) {
    int i;
    pthread_t t;
    srandom(time(NULL));
    mutex=semaphore_create(1);
    ok2read=semaphore_create(0);
    ok2write=semaphore_create(0);
    for (i=0; i<NUMBER_OF_READERS; i++)
        pthread_create(&t, NULL, reader, (void *)(uintptr_t) i);
    for (i=0; i<NUMBER_OF_WRITERS; i++)
        pthread_create(&t, NULL, writer, (void *)(uintptr_t) i);
    while(1)
        pause();
}

wlast non serve più... Renzo (talk) 17:52, 13 November 2016 (CET)

RW2bis

Nella tua soluzione se i lettori sono "molto veloci" e non vanno mai a 0, lo scrittore non inizierà mai a scrivere.

Cioè: Uno scrittore viene svegliato da ok2write solo se passa la condizione

[..] 
if (numberofReaders == 0 && waitingWriters >0) 
     semaphore_V(ok2write);
[..]

--GabrieleCalarota (talk) 17:46, 13 November 2016 (CET)

Non direi perche' nella startread se:

    if (numberOfWriters > 0 || waitingWriters>0)

i lettori si bloccano. Quindi se c'e' almeno uno scrittore in attesa i lettori non entrano (e quindi prima o poi terminano e lasciano il posto ad uno scrittore). Renzo (talk) 17:57, 13 November 2016 (CET)


Ho pensato al caso limite seguente: Supponiamo che ci siano dei lettori che stanno leggendo e ad un certo punto uno scrittore chiede di scrivere.

         
       void startread(void) {
    // <await nw == 0 -> nr++>
    semaphore_P(mutex);
    if (numberOfWriters > 0 || waitingWriters>0) {
        waitingReaders++;   //Nuovo scrittore (t1)
        semaphore_V(mutex);
        semaphore_P(ok2read);
        waitingReaders--;
    }
    numberOfReaders++;
    w_last=0;
    printf("NR %d - NW %d - WR %d - WW %d \n", numberOfReaders, numberOfWriters, waitingReaders, waitingWriters);
   if (waitingReaders > 0 )   //Vecchio scrittore(t1)
        semaphore_V(ok2read);
    else
        semaphore_V(mutex);
}

Non appena lo scrittore rilascia il mutex, un nuovo scrittore chiede di leggere (e si addormenterà). Un lettore (lento) che era riuscito a entrare nel segmento startofread prima che lo scrittore entrasse in startofwrite, continua a leggere e risveglia uno dei nuovi lettori. Se i lettori continuano a richiedere di leggere continuamente, verranno addormentati e subito risvegliati.

E' da considerarsi possibile? --GabrieleCalarota (talk) 19:11, 13 November 2016 (CET)

Suppongo che "un nuovo scrittore chiede di leggere" si aun refuso e sia da intendere "un nuovo lettore chiede di leggere" (altrimenti ci sono crisi di identità) e che "startofread" significhi "startread" e "startofwrite" sia "startwrite". La "startread" viene eseguita in mutua esclusione, quindi non ci puo' essere "un lettore lento che sia riuscito ad entrare" nella funione startread. Se ha superato la P(mutex) iniziale o e' bloccato sulla ok2read o e' entrato. Renzo (talk) 19:37, 13 November 2016 (CET)