Domanda

Ho uno scenario quando inizio 3..10 fili con ThreadPool. Ogni thread fa il suo lavoro e restituisce al ThreadPool. Quali sono le possibili opzioni da notificati nel thread principale quando tutti i thread in background hanno finito?

Al momento sto usando un metodo homegrown con incrementare una variabile per ognuno dei thread creati e decremento quando un thread in background sta per finire. Questo funziona bene, ma ero curioso di sapere se ci sono opzioni migliori.

È stato utile?

Soluzione

decremento di una variabile (tra i thread) è un po 'rischioso se non fatto con Interlocked.Decrement, ma tale approccio dovrebbe andare bene se si ha l'ultimo filo (vale a dire quando si arriva a zero) generare un evento. Si noti che avrebbe dovuto essere in un "finalmente" blocco per evitare di perdere in caso di eccezioni (più non si vuole uccidere il processo).

In "Estensioni paralleli" (o con .NET 4.0), si potrebbe anche guardano le Parallel.ForEach opzioni qui ... che potrebbe essere un altro modo di ottenere tutto fatto come un blocco. Senza dover guardare tutti manualmente.

Altri suggerimenti

Prova questo: https://bitbucket.org/nevdelap/poolguard

using (var poolGuard = new PoolGuard())
{
    for (int i = 0; i < ...
    {
        ThreadPool.QueueUserWorkItem(ChildThread, poolGuard);
    }
    // Do stuff.
    poolGuard.WaitOne();
    // Do stuff that required the child threads to have ended.

void ChildThread(object state)
{
    var poolGuard = state as PoolGuard;
    if (poolGuard.TryEnter())
    {
        try
        {
            // Do stuff.
        }
        finally
        {
            poolGuard.Exit();
        }
    }
}

PoolGuards multipli possono essere utilizzati in modi diversi per tenere traccia quando le discussioni sono finite, e maniglie fili che non hanno iniziato quando la piscina è già chiuso.

Se le sue non più di 64 thread di aspettare, è possibile utilizzare il metodo WaitHandle.WaitAll in questo modo:

List<WaitHandle> events = new List<WaitHandle>();
for (int i = 0; i < 64; i++)
{
    ManualResetEvent mre = new ManualResetEvent(false);
    ThreadPool.QueueUserWorkItem(
        delegate(object o)
        {
            Thread.Sleep(TimeSpan.FromMinutes(1));
            ((ManualResetEvent)o).Set();
        },mre);
    events.Add(mre);
}
WaitHandle.WaitAll(events.ToArray());

L'esecuzione attenderà fino a che tutti ManualResetEvents sono impostati, in alternativa, è possibile utilizzare il metodo WaitAny.

I metodi WaitAny e WaitAll potranno bloccare l'esecuzione, ma si può semplicemente utilizzare l'elenco, o un dizionario di ManualResetEvents legati al compito che è di spawn per dopo determinare se il filo è fatto però.

Non c'è non è un modo integrato per effettuare questa operazione in questo momento -. Trovo uno dei più grandi dolori sull'utilizzo discussioni piscina

Come dice Marc, questo è il genere di cose che viene fissato in estensioni Parallel / .NET 4.0.

Non potresti dare ad ogni filo di un ManualResetEvent distinto e avere ogni set l'evento quando fatto. Poi, nel thread principale si può attendere su tutti gli eventi passati in.

La soluzione di Marc è migliore se si vuole solo sapere quando tutti i lavori sono finiti, e non è necessario informazioni più fine di quella (come sembra essere il vostro caso).

Se si voleva un po 'di filo per deporre le uova di posti di lavoro, e qualche altro thread per ricevere le notifiche, è possibile utilizzare WaitHandle. Il codice è molto più lungo.

    int length = 10;
    ManualResetEvent[] waits = new ManualResetEvent[length];
    for ( int i = 0; i < length; i++ ) {
        waits[i] = new ManualResetEvent( false );
        ThreadPool.QueueUserWorkItem( (obj) => {
            try {

            } finally {
                waits[i].Set();
            }
        } );
    }

    for ( int i = 0; i < length; i++ ) {
        if ( !waits[i].WaitOne() )
            break;
    }

Il metodo WaitOne, come scritto, restituisce sempre vero, ma ho scritto in quel modo di fare ti ricordi che alcuni sovraccarichi prendere un timeout come argomento.

Cosa succede ad usare i semafori, e impostare un limite ad esso tanto quanto il vostro pool di thread. Avere un metodo per andare a prendere un semaforo, per essere chiamato quando si avvia il filo, rilasciarlo quando la vostra estremità del filo e sollevare un evento se hai preso tutta la semaforo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top