2012-02-24 12 views
5

ho riutilizzato la coda dei consumatori esempio produttore dal C# in un libro Nutshell di Albahari (http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT) e un collega osservai: "Perché non è il Dispose invitato la BlockingCollection nel Dispose della collezione? "chiamando Dispose su un BlockingCollection <T>

Non sono riuscito a trovare una risposta e l'unica ragione per cui posso venire è che l'esecuzione del carico di lavoro rimanente della coda non sarebbe stata elaborata. Tuttavia, quando sto eliminando la coda, perché non dovrebbe interrompere l'elaborazione?

Oltre al "Perché non si deve smaltire BlockingCollection?" Ho anche una seconda domanda "Ti fa male se non disponga un BlockingCollection?". Suppongo che quando si generano/eliminano molte code di consumo da parte dei produttori, questo crea problemi (non che io voglia ciò, ma solo per la causa della conoscenza). Secondo What does BlockingCollection.Dispose actually do? BlockingCollection contiene due handle di attesa (ovviamente), quindi non chiamare Dispose vi darà alcuni problemi. Grazie a ken2k per averlo indicato.

Il codice di cui sto parlando:

public class PCQueue : IDisposable 
{ 
    BlockingCollection<Action> _taskQ = new BlockingCollection<Action>(); 
    public PCQueue (int workerCount) 
    { 
    // Create and start a separate Task for each consumer: 
    for (int i = 0; i < workerCount; i++) 
     Task.Factory.StartNew (Consume); 
    } 

    public void Dispose() { _taskQ.CompleteAdding(); } 

    public void EnqueueTask (Action action) { _taskQ.Add (action); } 

    void Consume() 
    { 
    // This sequence that we’re enumerating will block when no elements 
    // are available and will end when CompleteAdding is called. 
    foreach (Action action in _taskQ.GetConsumingEnumerable()) 
     action();  // Perform task. 
    } 
} 
+2

Forse correlato: http://stackoverflow.com/questions/3188601/what-does-blockingcollection-dispose-actually-do – ken2k

+0

Ho riscontrato problemi con l'eliminazione della raccolta di blocchi (ad esempio, rilasciare l'ultima volta), fino a quando non ho iniziato a utilizzare CancellationToken, vedere https://stackoverflow.com/a/5759866/1544054 – Aviko

risposta

7

Perché sarebbe un errore. La raccolta non può essere eliminata fino all'esaurimento di tutti i thread del consumatore. Se questo non è interbloccato, quei thread bombarderebbero con un'eccezione. La classe non ha in alcun modo la consapevolezza di ciò che i thread dei consumatori potrebbero trarre dalla raccolta, quindi non può ragionevolmente sapere quando è sicuro di disporre. Tutto ciò che può fare è impedire che altri oggetti vengano aggiunti dal produttore, è ragionevole.

Questo è un problema comune con i thread, lo smaltimento sicuro richiede di sapere quando il thread è completo. Che spesso sconfigge il punto di utilizzo dei thread in primo luogo, non vuoi aspettare fino alla fine di un thread. Questo è più visibile nella classe Thread stessa, consuma cinque handle nativi del sistema operativo ma non ha un metodo Dispose(). Devono essere rilasciati dal finalizzatore. Anch'io.