Newsgroup: it.comp.lang.c++
Titolo: threads in c++: produttore-consumatore

Salve a tutti!
dispongo di una classe MutexLock che mi fornisce i seguenti metodi
* lock()
*unlock()
per gestire l'accesso mutuamente esclusivo ad una risorsa.
Quello che vorrei scrivere è un programma che abbia 2 threads, un produttore 
e un consumatore usando un buffer di comunicazione.In giro per internet ho 
letto che dovrei fare uso dell' oggetto di tipo Semaforo, aventi questi due 
metodi:
wait() - lancia una richiesta per ottenere l'uso esclusivo della risorsa 
condivisa e si mette in attesa finche' non lo ottiene
signal() - libera la risorsa
Mi occorrono per il mio esempio quindi 2 oggetti di tipo Semaforo:
- vuoti
- pieni
 Il produttore produce un prodotto solo quando il buffer ha spazio (a questo 
ci pensa il semaforo vuoti), e il consumatore consuma il prodotto che trova 
dentro il buffer (l'accesso al buffer per il consumatore è regolato dal 
semaforo pieni)
Sostanzialmente il codice per i due Threads è il seguente:
<produttore>
void run(){
while(!fine){
    vuoti.wait();    //c'è spazio nel buffer per inserire un prodotto?
    <produce elemento e lo pone nel buffer>
    pieni.signal();  // avverto il consumatore che c'è un prodotto da 
consumare!
    }
}
<consumatore>
void run(){
while(!fine){
    pieni.wait();    // ci sono prodotti da consumare nel buffer?
    <estrae un elemento dal buffer e lo consuma>
    vuoti.signal(); //c'è uno spazio vuoto in piu' che puo' essere riempito 
dal produttore
    }
}
ecco..il problema è che io lo so fare in java, __pero' non in c++__.
Alcuni quesiti:
1. prima di tutto, ho veramente bisogno di creare tutto questa montagna di 
codice o posso utilizzare solo lock e unlock?
2. in java ci sono i blocchi synchronized, in c++ come faccio?
3. infine, se qualcuno ha gia' risolto questo quesito, beh se lo posta mi fa 
un gran piacere!!
Giacomo 

 per gestire l'accesso mutuamente esclusivo ad una risorsa.
Abbastanza assurdamente, leggendo il titolo del tuo post ho pensato che 
parlasse della statistica di chi posta messaggi qui, di chi li legge e 
di chi risponde... ci ho messo un pò a capire che parlavi di semafori e 
sincronizzazione :-)
Il C++ non gestisce direttamente semafori e mutex, che sono specifici 
del sistema su cui il codice viene fatto girare. Ti conviene 
documentarti sulle API di windows, supposto che lavori su windows, e 
vedere che API ti servono (tiro a indovinare: CreateMutex() e 
CreateMutexEx()?) e come usarle.

 CreateMutexEx()?) e come usarle.
Forse boost::thread e' piu' simile a quello che cerca, ammesso che fosse 
questa la domanda.
  bye
	av.

 
Come qualcuno ha già detto, il linguaggio C++ non prevede costrutti legati
alla sincronizzazione dei thread.
Per garantire che l'esecuzione di un certo blocco venga serializzata,
solitamente si adotta un idioma che sfrutta l'inizializzazione e la
distruzione deterministica di un oggetto per acquisire e rilasciare un
mutex.
Vedi sezione "4. The Scoped Locking Idiom" (pagina 6) in 
 
http://www.cs.wustl.edu/~schmidt/PDF/locking-patterns.pdf
Max

 un gran piacere!!
vedi boost:thread, Loki, txObject su google.
Cerca mutex su wikipedia.
Ciao,
Cesare

 ha scritto nel messaggio 
news:WyMkh.93157$Fk1.4...@twister2.libero.it...

si penso anch'io che boost:thread sia quello che cerco, anche perchè 
utilizza i costrutti
- wait()
- notify()
- notifyAll()
che sono quelli che cerco.
Grazie mille!
Giacomo 

 ha scritto nel messaggio 
news:en05u1$dng$1...@newsreader.mailgate.org...


 Cesare
boost:thread sembra perfetta, adesso la provo!
Giacomo 

 Ecco perchè preferirei usare due semafori numerici.
E per fare questo servono 2 semafori?
Facciamo le cose semplici.
Supponi di avere una classe Mutex che ha 2 metodi: acquire e release.
acquire e` *bloccante*, nel senso che se il Mutex e` stato preso il 
thread chiamante viene bloccato.
Poi c'e` una classe Buffer con metodi read e write non thread-safe.
write lancia una eccezione se il buffer e` pieno.
read invece lascia invariato l'oggetto Data (oggetto cella) se non c'e` 
niente da leggere.
Scrivo un modulo buffer.cpp con 2 funzioni:
#include "mutex.h"
#include "buffer.h"
static Mutex lock;
static Buffer buffer;
// chiamata solo da un thread consumatore
void read_buf(Data& data) {
     lock.acquire(); // un thread consumatore viene bloccato se un 
produttore sta scrivendo
     buffer.read(data);
     lock.release();
}
// chiamata solo da un thread produttore
void write_buf(Data& data) {
     lock.acquire(); // un thread produttore viene bloccato se un 
consumatore sta leggendo
     try {
        buffer.write(data);
     }
     catch (BufferExcept& e) {
         // se il buffer e` pieno rilascia il lock
         // eventualmente rilancia l'eccezione BUFFER_FULL al chiamante
         // di write_buf
         lock.release();
     } // gestisci altre eccezioni e rilascia il lock
     // e` riuscito a scrivere
     lock.release();
}
write_buf si potrebbe semplificare togliendo il try catch e usando un 
oggetto guardia sul Mutex, cioe` un oggetto su stack che chiama 
lock.acquire nel costruttore e lock.release nel distruttore.
Questa tecnica permette in genere di scrivere codice piu` except-safe 
perche` toglie la coppia di chiamate acquire/release e non si rischia di 
avere un deadlock perche` si dimentica di chiamare release in qualche 
eccezione non gestita.
Ciao,
Cesare

 Facciamo le cose semplici.
Ma le hai fatte troppo semplici. :)
La tua soluzione non affronta alcuni requisiti fondamentali. I consumatori
devono restare in attesa finché un produttore non produce qualcosa.
Analogamente, i produttori devono restare in attesa se non c'è spazio
libero. Nel tuo codice, invece, i consumatori devono continuamente invocare
una funzione per vedere se c'è qualcosa per loro, mentre i produttori
generano un errore ogni volta che i consumatori non consumano abbastanza
velocemente.
Per implementare decentemente una coda inter-thread occorre un meccanismo di
segnalazione. Ad esempio, una "conditional variable". Anzi, ce ne vogliono
due. Internet è ricchissima di letteratura a riguardo.
Max


Non avevo capito che c'erano questi requisiti.
Mi ero messo nell'ottica di proteggere il buffer e basta e avevo anche 
dichiarato la banalita` della soluzione.
Ciao,
Cesare


Effettivamente.
Ecco un esempio in C++
http://www.cs.mtu.edu/~shene/NSF-3/e-Book/SEMA/TM-example-buffer.html

 ha scritto nel messaggio 
news:11674076...@sj-nntpcache-1.cisco.com...

Si in effetti mi ero spiegato male, scusatemi.
Quello che devo fare io è sincronizzare i due thread,e quindi ho bisogno di 
un meccanismo di segnalazione.
Con un solo mutex sul buffer impedisco l'accesso simultaneo alla risorsa, ma 
non sincronizzo i due threads.
Giacomo