Angella Andrea - Italian Blog

Infinita passione per lo sviluppo software !
posts - 133, comments - 216, trackbacks - 9

My Links

News

MIT OpenCourseWare: I'm invested Wikipedia Affiliate Button


Sto leggendo:

Archives

Post Categories

Siti web realizzati

Siti web tecnici

[70-536] - AutoResetEvent e ManualResetEvent


Area di riferimento

- Implementing service processes, threading, and application domains in a .NET Framework application
   - Develop multithreaded .NET Framework applications
      - AutoResetEvent class and ManualResetEvent class
      - EventWaitHandle class, RegisterWaitHandle class, SendOrPostCallback delegate and IOCompletionCallback delegate



EventWaitHandle

L'oggetto EventWaitHandle ( e gli oggetti derivati AutoResetEvent e ManualResetEvent ) permette di gestire attraverso segnali la sincronizzazione tra diversi thread.

I metodi principali sono:

  • Set() che imposta lo stato dell'evento a segnalato, permettendo a uno o più dei thread in attesa di procedere
  • Reset() che imposta lo stato dell'evento a non segnalato, che causerà il blocco dei thread
  • WaitOne() che blocca il thread corrente se l'evento non è segnalato altrimenti concede l'accesso.

La differenza tra un AutoResetEvent e un ManualResetEvent è semplicemente che dopo la WaitOne() nel primo caso viene effettuato il Reset() in automatico mentre nel secondo caso bisognerà gestire manualmente il reset dell'evento.

Per vedere in azione questa classe consideriamo un esempio. Supponiamo di avere un unico thread produttore e diversi thread consumatori. Il dato prodotto dal produttore è un numero intero. Si vuole fare in modo che una volta prodotto il dato il produttore si metta in attesa che venga consumato da qualche consumatore e che ciascun consumatore si metta in attesa che un dato venga prodotto ( non ho realizzato un meccanismo bufferizzato per semplicità ).

class Program
{
    private const int N_COMSUMATORI = 5;           // numero totale dei consumatori
    private const int N_LETTURE = 3;               // numero totale di letture per consumatore

    private static EventWaitHandle datoPronto;     // segnalato quando il dato è pronto
    private static EventWaitHandle datoLetto;      // segnalato quando il dato è stato letto

    private static int cont = 1;                   
    private static int dato = 0;                   // zona di memoria condivisa per la memorizzazione del dato

    public static void Main(string[] args)
    {
        Thread[] threadConsumatori;    
        Thread threadProduttore;       

        // Costruisco gli oggetti EventWaitHandle impostati opportunamente
        datoPronto = new EventWaitHandle(false, EventResetMode.AutoReset);
        datoLetto = new EventWaitHandle(true, EventResetMode.AutoReset);

        threadConsumatori = new Thread[N_COMSUMATORI];

        // Faccio partire i thread consumatori
        for (int i = 0; i < N_COMSUMATORI; i++)
        {
            threadConsumatori[i] = new Thread(new ParameterizedThreadStart(consumatore));
            threadConsumatori[i].Start(i);
        }

        // Faccio partire il thread produttore
        threadProduttore = new Thread(produttore);
        threadProduttore.Start();

        // Attendo che tutti i consumatori abbiano finito
        for (int i = 0; i < N_COMSUMATORI; i++)
        {
            threadConsumatori[i].Join();
        }

        // termino il processo produttore
        threadProduttore.Abort();

        Console.Write("Fine");
        Console.ReadKey();
    }

    public static void consumatore(object info)
    {
        int id = (int)info;

        for(int i=0; i<N_LETTURE; i++)
        {
            // Attendo che un dato sia pronto
            datoPronto.WaitOne();

            // Utilizzo il dato
            Console.WriteLine("Consumatore {0}: letto {1}", id, dato);
            Thread.Sleep(1000);

           // Segnalo che il dato è stato letto
            datoLetto.Set();
        }

        Console.WriteLine("Consumatore {0} ha terminato", id);
    }

    
    public static void produttore(object info)
    {
        while ( true )
        {
            // attende che l'ultimo dato scritto venga consumato
            datoLetto.WaitOne();

           // produce un nuovo dato
            dato = cont++;
            Thread.Sleep(1000);
            Console.WriteLine("Produttore: ho prodotto {0}", dato);

            // segnala che un nuovo dato è pronto per essere consumato
            datoPronto.Set();
        }

        Console.WriteLine("Il produttore ha terminato");
    }

}


Ecco come si presenta l'output di una possibile esecuzione di questo codice:

Produttore: ho prodotto 1
Consumatore 3: letto 1
Produttore: ho prodotto 2
Consumatore 3: letto 2
Produttore: ho prodotto 3
Consumatore 3: letto 3
Consumatore 3 ha terminato
Produttore: ho prodotto 4
Consumatore 0: letto 4
Produttore: ho prodotto 5
Consumatore 0: letto 5
Produttore: ho prodotto 6
Consumatore 0: letto 6
Consumatore 0 ha terminato
Produttore: ho prodotto 7
Consumatore 1: letto 7
Produttore: ho prodotto 8
Consumatore 1: letto 8
Produttore: ho prodotto 9
Consumatore 4: letto 9
Produttore: ho prodotto 10
Consumatore 4: letto 10
Produttore: ho prodotto 11
Consumatore 1: letto 11
Consumatore 1 ha terminato
Produttore: ho prodotto 12
Consumatore 2: letto 12
Produttore: ho prodotto 13
Consumatore 2: letto 13
Produttore: ho prodotto 14
Consumatore 2: letto 14
Consumatore 2 ha terminato
Produttore: ho prodotto 15
Consumatore 4: letto 15
Consumatore 4 ha terminato
Fine


In particolare nell'esempio vengono utilizzati due oggetti EventWaitHandle uno datoPronto viene utilizzato dal produttore per segnalare quando un nuovo dato è disponibile mentre l'altro datoLetto viene utilizzo dal consumatore per segnalare al produttore che il dato appena prodotto è stato correttamente consumato.

E' importante notare che l'oggetto EventWaitHandle costruito utilizzando il valore EventResetMode.AutoReset corrisponde all'oggetto AutoResetEvent. L'oggetto EventWaitHandle costruito utilizzando il valore ManualResetMode.ManualReset corrisponde invece all'oggetto ManualResetEvent.

La classe RegisterWaitHandle e in particolare il suo metodo RegisterWaitForSingleObject() viene invece utilizzata per eseguire un metodo di callback quando uno specifico wait handle viene segnalato.
Per maggiori dettagli guardare l'esempio su msdn al seguente indirizzo http://msdn2.microsoft.com/en-us/library/system.threading.registeredwaithandle.aspx

Print | posted on domenica 30 marzo 2008 17:21 | Filed Under [ Exam 70-536 Application Development Foundation ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET