eccoci con la 3 parte del piccolo corso sui thread in c#. un altro problema che può verificarsi molto spesso è il voler compiere un’azione asincrona ma non volere che il thread principale continui finchè questi non abbia finito l’operazione, è in pratica un’operazione di sincronizzazione fra thread. c’è da chiedersi allora il perchè non fare direttamente un’operazione sincrona… i motivi ci sono, primo fra tutti il non voler intasare troppo il thread principale oppure voler fare altre operazioni prima di mettersi in attesa… ecco perciò che ci viene in aiuto l’oggetto EventWaitHandle.
posizioniamoci prima della richiesta asincrona e assegnamo un nuovo oggetto all’istanza:
EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
a questo punto chiamiamo il nuovo thread come da codice visto in precedenza.
ThreadStart entry = new ThreadStart(CheckFile); Thread thread = new Thread(entry); thread.Start();
facciamo tutto quello che vogliamo fare e poi mettiamoci in pausa in attesa della fine del thread, magari con un timeout di 20 secondi ad esempio:
if (!waitHandle.WaitOne(20000, true))
{
//gestione dell'errore
}
adesso, in un punto qualsiasi della vita del thread parallelo, nel momento in cui vogliamo risvegliare il thread principale, settiamo l’handle da noi messo in pausa:
waitHandle.Set();
a questo punto il thread principale si sveglierà e noi saremmo in grado di continuare.
di seguito un codice di esempio:
Mi chiamo Denis Billi, ho 25 anni e sono della provincia di Ravenna. Mi sono laureato nell'estate del 2008 presso la facoltà di Ingegneria Informatica dell'università di Bologna e attualmente sto seguendo i corsi per la Laurea Specialistica in Ingegneria Informatica sempre all'università di Bologna.
Ciao, grazie per la tua soluzione mi è tornata utile.
Personalmente l’ho modificata un po’ avendo un Main Thread che fa partire n Threads figli ho risolto in questo modo
//nel main thread EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); for (int i= 0 ;i< n; i++) { lancio threadFigli(waitHandle) } for (int i= 0 ;i< n; i++) { waitHandle.WaitOne() } //all'interno di ogni Thread figlio //work waitHandle.set();in questo modo il main thread si mette in attesa tante volte quanti thread figli partono e procede mano mano che ritornano.
Secondo te è una buona soluzione?
ciao!
Ciao Gianlu. Guarda come dico spesso negli articoli, ogni soluzione è ottima per quello che si vuol fare, dipende dallo stile di programmazione, dal problema iniziale e soprattutto dalle conoscenze del programmatore.
Nel tuo caso particolare, mi pare di aver capito che hai la necessità di sincronizzare l’avvio ed il termine di N thread di cui il Main è il padre. Una volta terminati tutti i thread, allora il Main tornerà a svolgere il suo lavoro.
A questo punto direi che in linea di massima la tua soluzione funziona, tuttavia ti faccio un paio di appunti:
Grazie per il tuo contributo!
Ciao, ho letto l’articolo e mi sembra molto utile ma non è ancora quello che vorrei fare.
Ti spiego brevemente: avrei bisogno di lanciare uno stesso metodo con parametri diversi da n thread diversi (per esempio 3 thread) e attendo un valore di ritorno dal metodo. In base a questo valore decido se rieseguire il thread con gli stessi parametri o con parametri diversi.
Hi qualche suggerimento in merito?
grazie per la disponibilità
Ciao Ervis! Scusami ma non ho ben capito la tua domanda: chiamare un metodo con “parametri diversi” non ha propriamente senso, perchè un metodo è fisso e perciò i parametri (la signature del metodo) è dichiarata a priori in fase di codifica, a run-time non si può modificare… questo soprattutto considerando che tu vorresti avere N possibilità. Sei sicuro che sia la via risolutiva migliore?
Fammi sapere.
ciao grazie per la risposta innanzitutto.
scusami ma mi sono espresso male io, chiaramente non si può fare quello che intendevo è “parametri con valori diversi”.
mi spiego meglio, il mio è un metodo semplicissimo es.:
bool MioMetodo(int param1, string param2)
{ … }
io vorrei chiamare questo metodo ad esempio da 3 thread diversi e appena ricevo il valore booleano di ritorno faccio le mie considerazioni e decido quale operazione eseguire successivamente.
il mio obiettivo è quello di eseguire una lista di richieste in più breve tempo. non so se sono riuscito a spiegarmi…
grazie ancora
Ciao di nuovo! Da quello che mi dici non c’è nulla di particolarmente complicato:
Fammi sapere se era questo che volevi sapere.
A presto!
grazie ancora per la risposta, mi manca ancora un pezzo, facciamo un esempio:
ho una lista di operazioni da fare che mi chiedono la consultazione verso dei dispositivi. per es. 100 operazioni e ho 3 dispositivi attaccati al pc, quindi uso 3 thread per consumare più velocemente la mia lista anzichè uno per volta
le voglio fare con un ciclo(non so se sia la strada giusta):
while (i<=100)
{
// come faccio a chiamare il thread con i 2 parametri in ingresso
// ed aspettarmi una risposta dal metodo chiamato (in questo caso
// booleano)? bisogna considerare che quando un thread finisce lo
// faccio ripatire (o ne creo uno nuovo non so) per poter eseguire
// l'operazione successiva finchè non sono arrivato a 100
}
—————————————
metodo da richiamare:
bool MioMetodo(int param) { … }
spero di non aver complicato ulteriormente le cose…
Hmm sembra che tu abbia un pò di confusione. Un thread non è una cosa che tu puoi chiamare a tuo piacimento per fargli fare quello che vuoi, bensì è un’entità attiva che nasce, vive e muore. Mi spiego meglio: tu crei il thread, gli fai eseguire un compito ed infine questo muore. Una volta che è morto non puoi farlo “rivivere”, ma devi crearne un altro che a sua volta farà qualcos’altro. Quello che farei io per risolvere il tuo problema (in base a quello che mi hai detto), è suddividere il lavoro tra i 3 thread, del tipo:
Fammi sapere se può andar bene.
A presto
è vero non ci avevo pensato, o meglio mi ero fissato del fatto che il ciclo glielo facevo, non all’interno del thread come giustamente dici tu (se ho capito bene), ma i thread stessi erano all’interno del cliclo.
mi sono venuti dei dubbi: 
con questa soluzione che mi sembra possa andare bene
1. premetto che la lista delle operazioni da fare la prendo con una select dal database, non è che potrei correre il pericolo che 2 thread diversi mi facciano la stessa operazione dato che l’operzione stessa, prima che sia finita dura dai 2 ai 3 secondi? dovrei mettere un lock quando interrogo il database? o dovrei segnare sul db la riga come impegnata? o non so??
2. come faccio a chiamare un metodo (es. bool MioMetodo(int param)) dal mio thread in modo che mi rotorni un valore, in questo caso booleano?
3. il metodo MioMetodo dovrebbe scrivere dei log sullo stesso file che però in questo caso anrebbe in conflitto dato che più thread potrebbero scrivere contemporaneamente…come posso fare? creo n file diversi quanti sono i thread?
Allora, una cosa alla volta:
Spero di essere stato chiaro, purtroppo il problema della concorrenza non è subito facile… fammi sapere!
grazie per il suggerimento della QueueList lo terrò in considerazione
Il thread è una classe che può eseguire del codice… nel codice ci sarà la chiamata al metodo… mi spiego? ok ora ho capito
Per la scrittura concorrente potresti affidarti sempre ad una classe che è abilitata da semafori… avresti mica qualche piccolo esempio?
grazie di tutto, mi hai schiarito le idee un bel po’
Certo, puoi dare un’occhiata qui che spiega molto bene cosa devi fare: Istruzione Lock (C#)
In pratica fai una classe Log con all’interno un metodo log(stringa) al cui interno fai un lock su un oggetto privato della classe al cui interno a sua volta fai la scrittura su file. Al resto ci pensa il framework.
A presto!
gentilissimo
grazie mille
Di nulla figurati! A presto!