Visualizzazione dei risultati da 1 a 5 su 5
  1. #1

    [JAVA] produttori, consumatori e lettori

    Ciao a tutti, sto entrando nel mondo della programmazione ad oggetti, ed ho un dubbio riguardo produttori consumatori ecc..
    In pratica sto cercando di fare un esercizio e non so se lo sto facendo bene. Tralasciando creazioni di classi e cose varie, il fulcro è: devo utilizzare 3 thread per gestire una TreeMap:

    Thread 1: inserisce un nuovo elemento nella mappa...
    l'inserimento deve essere concorrente rispetto agli altri thread, secondo uno schema di produttori/consumatori

    Thread 2: visualizza dei dati della mappa...
    la lettura deve essere concorrente rispetto gli altri thread, secondo uno schema di lettori/consumatori

    Thread 3: cancella degli elementi dalla mappa...
    l'eliminazione deve essere concorrente rispetto agli altri thread, secondo uno schema di produttori/consumatori.


    Ora io questa cosa la intendo così: thread 1 è un produttore, thread 3 è un consumatore, thread 2 è un lettore e Thread1-thread3 si possono intendere come "scrittori".

    Se non sbaglio, nello schema produttori/consumatori, nel metodo "put" (quello del produttore) il thread si deve mettere in wait() quando la mappa è piena, mentre nel metodo "remove" (quello del consumatore) il thread si deve mettere in wait() quando la mappa è vuota.

    Mentre nello schema lettori/scrittori, un lettore non può leggere durante la scrittura di uno scrittore (e viceversa) quindi per esempio (nel mio caso) uso i lock (e quindi il lettore se writeLock è true aspetta, se false va, mentre uno scrittore se readLock è true aspetta altrimenti va). Giusto fin qui?

    Se è giusto, l'esercizio che ho appena scritto, sarebbe un insieme di queste cose, giusto?

    Quindi sarebbe una cosa del tipo:

    /*produttore*/
    while (readLock || "mappa piena")
    wait();


    /*consumatore*/
    while (readLock || "mappa vuota")
    wait();


    /*lettore*/
    while (consLock || prodLock)
    wait();


    Confermate?
    Ultima modifica di gabriele90; 10-07-2015 a 21:10

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da gabriele90 Visualizza il messaggio
    Se non sbaglio, nello schema produttori/consumatori, nel metodo "put" (quello del produttore) il thread si deve mettere in wait() quando la mappa è piena, mentre nel metodo "remove" (quello del consumatore) il thread si deve mettere in wait() quando la mappa è vuota.
    Alt, quello che hai descritto è il classico funzionamento di una "coda". Una coda sostanzialmente è un "tubo" con due soli estremi. Se la coda è vuota, un lettore si blocca mentre se la coda è di tipo "bounded" (limitata a max N elementi) ed è piena allora uno scrittore si blocca.
    Per le code non ci sono dubbi, il senso è quello descritto. Tutte le code "bloccanti" sono così.

    Ma ..... per una mappa? Cosa vuol dire bloccarsi? Quale è il senso della attesa? Un lettore si blocca solo quando la mappa è vuota? Oppure si blocca quando la chiave che sta cercando non c'è nella mappa? O altro?

    Devi chiarire questi aspetti!

    E comunque, a parte i chiarimenti concettuali, quello che dovrai sicuramente fare è incapsulare il TreeMap di cui parli, ovvero creare una classe che contiene il TreeMap e che nasconde tutta la logica di sincronizzazione/attesa, in modo che i "client" (chi userà la tua classe) non debbano preoccuparsi di questi aspetti.

    E infine, tieni presente che se la attesa del lettore che vuoi realizzare è quando la chiave cercata non è presente, sappi che è molto più tosto e critico (ma è assolutamente possibile). E se ci pensi/ragioni un attimo, capisci anche il perché.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Ma ..... per una mappa? Cosa vuol dire bloccarsi? Quale è il senso della attesa? Un lettore si blocca solo quando la mappa è vuota? Oppure si blocca quando la chiave che sta cercando non c'è nella mappa? O altro?
    Grazie per avermi risposto.
    Hai assolutamente ragione.
    Però sono stato impreciso io nella spiegazione, perchè l'esercizio dice che un lettore, se la chiave dell'elemento da leggere non è presente oppure se non ci sono elementi nella mappa, deve lanciare un'eccezione. Quindi questo discorso lo devo gestire così.
    Stessa cosa per i produttori, che lanciano un'ecezione se la mappa è piena (si per l'esercizio la mappa ha un limite), e per i consumatori, che lanciano un'eccezione se l'elemento da eliminare non c'è (quindi non c'è la chiave).

    I miei dubbi sono nella parte di esercizio dove dice "secondo uno schema di produttori/consumatori" e "lettori/scrittori". Ma in che senso? Questi schemi sono quelli che ho detto io (ovviamente sono da adattare alle mappe)?
    cioè (supponendo sia una coda) produttore/consumatore possono lavorare senza "disturbarsi" (nella coda il prod aggiunge elementi mentre cons elimina elementi dalla testa, quindi prod e cons non si toccano e possono lavorare contemporaneamente), prod aspetta solo quando la coda è piena mentre cons aspetta quando la coda è vuota; mentre lettore e scrittore non possono lavorare contemporaneamente, quindi se c'è un lettore che legge (quindi fissando il suo lock a true) lo scrittore deve aspettare, e viceversa.
    Se questi fossero gli schemi di cui l'esercizio parla, devono effettivamente essere adattati alle mappe, e non capisco come...
    Perchè se seguissi gli schemi che ho scritto, significherebbe che (lasciando stare le eccezioni), il produttore deve aspettare solo quando c'è il lettore che legge, il consumatore deve aspettare solo quando c'è il lettore che legge, il lettore deve aspettare se c'è il produttore o il consumatore che stanno "lavorando". E' corretto?

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da gabriele90 Visualizza il messaggio
    l'esercizio dice che un lettore, se la chiave dell'elemento da leggere non è presente oppure se non ci sono elementi nella mappa, deve lanciare un'eccezione.
    Stessa cosa per i produttori, che lanciano un'ecezione se la mappa è piena (si per l'esercizio la mappa ha un limite), e per i consumatori, che lanciano un'eccezione se l'elemento da eliminare non c'è (quindi non c'è la chiave).
    Allora scusa .... dove sta l'attesa? Cioè il concetto di "bloccante" dove entra in tutto questo?

    Quote Originariamente inviata da gabriele90 Visualizza il messaggio
    cioè (supponendo sia una coda) produttore/consumatore possono lavorare senza "disturbarsi" (nella coda il prod aggiunge elementi mentre cons elimina elementi dalla testa, quindi prod e cons non si toccano e possono lavorare contemporaneamente)
    Generalmente le code "sincronizzate"/"bloccanti" più semplici e basilari hanno un singolo lock, per cui c'è effettivamente mutua esclusione tra chi inserisce e chi estrae. Il lock comunque serve in questo caso sia per la atomicità sia per la visibilità delle modifiche da parte degli altri thread.
    Ma è perfettamente possibile creare una coda più sofisticata che permette una maggior concorrenza ... si tratta solo di sfruttare in modo migliore e più sofisticato le tecniche di locking.

    Per es. java.util.concurrent.ConcurrentLinkedDeque (da Java 7 in poi) è una "deque" (che sta per "double ended queue") è appunto una collezione in cui, come dice la documentazione: Concurrent insertion, removal, and access operations execute safely across multiple threads. Però è un-bounded (senza limite).
    EDIT: ho verificato bene adesso, ConcurrentLinkedDeque non è "bloccante". Era comunque solo come esempio di maggior concorrenza.

    Quote Originariamente inviata da gabriele90 Visualizza il messaggio
    Se questi fossero gli schemi di cui l'esercizio parla, devono effettivamente essere adattati alle mappe, e non capisco come...
    Quello che non è ancora chiaro è dove rientra il concetto di "bloccante" nel contesto chiesto/indicato da te.
    Ultima modifica di andbin; 11-07-2015 a 15:41
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Quote Originariamente inviata da andbin Visualizza il messaggio
    Quello che non è ancora chiaro è dove rientra il concetto di "bloccante" nel contesto chiesto/indicato da te.
    è esattamente quello che non riesco a capire...
    il testo dell'esercizio dice solo che

    - un thread si occupa di inserire un nuovo elemento nella mappa e lo deve fare concorrentemente rispetto agli altri thread, secondo uno schema di produttori/consumatori

    - un thread si occupa di leggere un elemento (data la sua chiave) dalla maooa e lo deve fare concorrentemente agli altri thread, secondo uno schema di lettori/scrittori

    - un thread si occupa di eliminare un elemento (data la sua chiave) dalla mappa e lo deve fare concorrentemente agli altri thread secondo uno schema di produttori/consumatori


    l'esercizio dice solo questo, e non riesco a capire quando devo bloccare e chi. Il fatto che si riferisca allo schema produttori/consumatori e allo schema lettori/scrittori, ed essendo una mappa comunque limitata (quindi una sorta di coda bounded), ho pensato che si dovesse fare come se fosse una coda bounded, quindi con le "regole" che ho descritto prima. Ma non mi convince tanto....

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.