2010-11-15 9 views
6

Vorrei realizzare una successiva comunicazione tra due thread:svegliare un thread quando si verifica un evento

filettatura Alpha fa qualcosa, e quindi si sospende. Quindi il secondo thread (Beta) genera ed evento che riprende il thread Alpha. Il ciclo continua ...

Ho fatto qualcosa di simile in basso ma non sono sicuro che sia un progetto adeguato. Inoltre ho notato che Thread.Suspend() e Thread.Resume() sono deprecati. Non vedo l'ora di ascoltare qualche consiglio su questa implementazione e quale è il metodo preferito per sostituire i metodi deprecati.

namespace ThreadTester 
{ 
    delegate void ActionHandler(); 

    class Alpha 
    { 
     internal Thread alphaThread; 
     internal void Start() 
     { 
      while (true) 
      { 
       this.alphaThread.Suspend(); 
       Console.WriteLine("Alpha"); 
      } 
     } 
     internal void Resume() 
     { 
      while (this.alphaThread.ThreadState == ThreadState.Suspended) 
      this.alphaThread.Resume(); 
     } 
    } 

    class Beta 
    { 
     internal event ActionHandler OnEvent; 
     internal void Start() 
     { 
      for (int i = 0; i < 15; i++) 
      { 
       OnEvent(); 
       Thread.Sleep(1000); 
      } 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Alpha alpha = new Alpha(); 
      alpha.alphaThread = new Thread(new ThreadStart(alpha.Start)); 
      alpha.alphaThread.Start(); 
      while (!alpha.alphaThread.IsAlive) ; 

      Beta beta = new Beta(); 
      beta.OnEvent += new ActionHandler(alpha.Resume); 
      Thread betaThread = new Thread(new ThreadStart(beta.Start)); 
      betaThread.Start(); 
     } 
    } 
} 

risposta

1

In genere i fili consentono di elaborare> 1 elemento di lavoro in parallelo. Sono curioso di sapere perché il tuo disegno richiede che il thread A dorma mentre il thread B fa qualcosa, quindi si sveglia e continua a lavorare. Perché non basta che il thread A funzioni autonomamente?

Si potrebbe trarre vantaggio dall'utilizzo di .Net 4 Task Parallel Library - thread A potrebbe quindi avviare un'attività asincrona che è automagicamente eseguito su un thread separato, e il risultato messo a disposizione di infilare un senza la necessità di esplicita segnalazione inter-thread (che può comportare un'app appesa in caso di malfunzionamento di Thread A o B).

12

Questo è dove in genere si utilizza wait handles, in particolare evento aspettare maniglie.

Se si chiama il metodo WaitOne su un handle di attesa, esso bloccherà il thread finché nessun altro thread chiama Set sullo stesso handle di attesa.

Esistono due importanti sapori semplici per le maniglie di attesa degli eventi: AutoResetEvent si ripristinerà automaticamente dopo un passaggio da WaitOne. ManualResetEvent si resetterà da solo se chiami Reset.

10

Si tratta di un problema di sincronizzazione comune e ci sono diversi approcci (che sono tutti abbastanza facile da rovinare, se non siete molto attenti):

  1. Maniglie attesa (Joren ha già descritto questi).

  2. Monitor.Wait e Monitor.Pulse. Una delle cose qui è che Pulse risveglierà solo i thread che sono già nello stato Wait, quindi devi stare attento a come gestisci il blocco dell'oggetto di sincronizzazione.

  3. Con il nuovo TPL in .NET 4 (anch'esso back-ported in .NET 3.5), è possibile impostare attività asincrone e definire le condizioni in cui le attività continuano in base alle attività completate in precedenza. C'è un po 'di una curva di apprendimento per capire come strutturare il codice per trarre vantaggio da Task e continuazione, ma è considerevolmente migliore (a lungo termine) rispetto alla strada molto rocciosa che segue l'ingannevolmente semplice uso dei costrutti di sincronizzazione di livello inferiore . Questo ti offre anche un eccellente percorso per aggiungere più robusta gestione degli errori e il supporto per l'annullamento alla tua logica, dato che i dettagli nitidi di coordinamento di questi sono integrati nel TPL.

7

Il tuo codice ha la "sensazione" del modello produttore-consumatore, ma implementato nel modo sbagliato. Sicuramente non vuoi usare Thread.Suspend e Thread.Resume in questo modo (o in qualsiasi modo in realtà).In realtà è facile ottenere il sequenziamento e la segnalazione nel modo desiderato, implementando il modello canonico produttore-consumatore tramite la classe BlockingCollection.

public class ProducerConsumer 
{ 
    private BlockingCollection<object> m_Queue = new BlockingCollection<object>(); 

    public ProducerConsumer() 
    { 
     new Thread(Producer).Start(); 
     new Thread(Consumer).Start(); 
    } 

    private void Consumer() 
    { 
     while (true) 
     { 
      object item = m_Queue.Take(); // blocks when the queue is empty 
      Console.WriteLine("Consumer"); 
     } 
    } 

    private void Producer() 
    { 
     while (true) 
     { 
      m_Queue.Add(new object()); 
      Thread.Sleep(1000); 
     } 
    } 
} 

Nel codice sopra Consumer e Producer sarebbe equivalente al vostro alphaThread e betaThread, rispettivamente.

+0

Questo è probabilmente il più vicino a rispondere al vero intento della domanda, anche se è difficile esserne certi. Il nuovo BlockingCollection è sicuramente un modo migliore per implementare questo semplice pattern Producer-Consumer piuttosto che utilizzare costrutti di sincronizzazione di basso livello direttamente. Detto questo, consiglierei all'OP di utilizzare questo modello con cautela, poiché ho visto che gli è sfuggito di mano (ho visto almeno un'applicazione con dozzine di thread che gestiscono il proprio gestore di messaggi 'Producer-Consumer' [con tre implementazioni del modello completamente diverse, nientemeno]).) –

Problemi correlati