2012-05-16 5 views
5

Sono un po 'nuovo in Multi-Threading e ho giocato solo con esso in passato. Ma sono curioso di sapere se è possibile avere un elenco di matrici di byte su un thread principale ed essere ancora in grado di aggiungere a quell'elenco mentre si crea il nuovo array di byte in un thread separato. Inoltre, userò un ciclo for-each che passerà attraverso un elenco di moduli che verranno utilizzati per analizzare l'array di byte. Quindi, in pratica una pseudo codice sarebbe stato così ...Come aggiungere a un elenco mentre si utilizza il multi-threading?

reports = new List(); 

foreach (form in forms) 
{ 
    newReport = new Thread(ParseForm(form)); 
    reports.Add(newReport); 

} 

void ParseForm(form) 
{ 
    newArray = new byte[]; 
    newArray = Convert.ToBytes(form); 
    return newArray; 
} 

Speriamo che la pseudo-codice fa un certo senso sopra. Se qualcuno potrebbe dirmi se è possibile e indicarmi la direzione di un buon esempio, sono sicuro di poter capire il codice reale.

+0

Dimenticato di menzionare, il webservice utilizza .Net 3.5 quindi non credo che le attività siano disponibili. – jhorton

risposta

3

Se è necessario accedere a una raccolta da più thread, si deve o la sincronizzazione uso, o utilizzare un SynchronizedCollection se il vostro. La versione NET è 3.0 o successiva.

Ecco un modo per rendere la collezione accessibile a tuo thread:

SynchronizedCollection reports = new SynchronizedCollection(); 

foreach (form in forms) { 
    var reportThread = new Thread(() => ParseForm(form, reports)); 
    reportThread.Start(); 
} 

void ParseForm(Form form, SynchronizedCollection reports) { 
    newArray = new byte[]; 
    newArray = Convert.ToBytes(form); 
    reports.Add(newArray); 
} 

Se siete su .NET 4 o versione successiva, una migliore alternativa a gestire manualmente le discussioni è presentato da varie classi della System.Threading.Tasks spazio dei nomi. Valuta la possibilità di esplorare questa alternativa prima di decidere sulla tua implementazione di threading.

+0

Grazie, dovrò provare il SynchronizedCollection poiché sono ancora in 3.5. – jhorton

+0

Devo impostare un riferimento per SynchronizedCollection? Ho le istruzioni using per Collections.Genereric e discussione. E ho controllato che stia usando 3.5, ma non sto ottenendo un SynchronizedCollection. – jhorton

+0

@jhorton È necessario aggiungere un riferimento a 'System.ServiceModel'. – dasblinkenlight

0

Why is enumerate files returning the same file more than once?

verificare che fuori. Mostra che penso esattamente cosa vuoi fare.

Crea un elenco sul thread principale e poi lo aggiunge da un thread diverso. vostra intenzione di bisogno

using System.Threading.Tasks 

-

Files.Clear(); //List<string> 

Task.Factory.StartNew(() => 
{ 
     this.BeginInvoke(new Action(() => 
     { 
      Files.Add("Hi"); 
     })); 
}); 
+1

Funziona solo se ** questo ** è un System.Windows.Forms.Control (o classi derivate). Non è un meccanismo di sincronizzazione ma un modo per interagire con l'interfaccia utente da altri thread. –

+0

Non posso discutere con quello. –

2

In prima abbiamo capito che era Net 3.5, conservare per riferimento .Net 4

Se non è necessario alcun ordine all'interno della lista, una semplice "correzione" è usare la classe ConcurrentBag<T> invece di una lista. Se hai bisogno di più ordini, c'è anche una collezione ConcurrentQueue<T>.

Se hai davvero bisogno di qualcosa di più personalizzato, puoi implementare la tua raccolta di blocchi utilizzando BlockingCollection <T>. Here's a good article sull'argomento.

È inoltre possibile utilizzare Parallel.ForEach di evitare la creazione di thread esplicito troppo:

private void ParseForms() 
{ 
    var reports = new ConcurrentBag<byte[]>(); 
    Parallel.ForEach(forms, (form) => 
           { 
            reports.Add(ParseForm(form)); 
           }); 

} 

private byte[] ParseForm(form) 
{ 
    newArray = new byte[]; 
    newArray = Convert.ToBytes(form); 
    return newArray; 
} 
+0

ConcurrentBag è solo 4.0 e superiore? – jhorton

+0

Sì, ho appena visto anche il tuo messaggio. Questo è incredibilmente facile con .Net 4.0 se puoi usarlo. –

+0

Devo essere d'accordo con te lì. Non sono sicuro del motivo per cui non hanno ancora aggiornato questo servizio a 4.0. Tutto il resto lo sta usando. – jhorton

0

Di seguito è una semplice raccolta di blocchi (solo come coda) che ho appena attivato ora poiché non si ha accesso a C# 4.0. Molto probabilmente è meno efficiente delle 4.0 insiemi concorrenti, ma dovrebbe funzionare abbastanza bene. Non ho re-implementato tutti i metodi Queue, semplicemente accodato, dequeue e sbircio. Se hai bisogno di altri e non riesci a capire come sarebbero implementati, menzionalo nei commenti.

Una volta creata la raccolta di blocchi di lavoro, è possibile aggiungerla semplicemente dai thread di produzione e rimuoverla utilizzando i thread di consumo.

public class MyBlockingQueue<T> 
{ 
    private Queue<T> queue = new Queue<T>(); 
    private AutoResetEvent signal = new AutoResetEvent(false); 
    private object padLock = new object(); 

    public void Enqueue(T item) 
    { 
     lock (padLock) 
     { 
      queue.Enqueue(item); 
      signal.Set(); 
     } 
    } 

    public T Peek() 
    { 
     lock (padLock) 
     { 
      while (queue.Count < 1) 
      { 
       signal.WaitOne(); 
      } 

      return queue.Peek(); 
     } 
    } 

    public T Dequeue() 
    { 
     lock (padLock) 
     { 
      while (queue.Count < 1) 
      { 
       signal.WaitOne(); 
      } 

      return queue.Dequeue(); 
     } 
    } 
}