2009-07-31 59 views
5

我正在編寫一個程序,我通常啓動五個線程。線程以不確定的順序返回。每個線程都調用一個返回List的方法。在.NET中返回數據的線程

我這樣做:所以在這裏

var masterList = List<string>();  
foreach (var threadParam in threadParams) 
{ 
    var expression = threadParam ; 
    ThreadStart sub =() => MyMethod(expressions); 
    var thread = new Thread(sub) 
    { 
     Name = expression 
    }; 

    listThreads.Add(thread); 
    thread.Start(); 
} 

var abort = true; 
while (abort) //Wait until all threads finish 
{ 
    var count = 0; 
    foreach (var list in listThreads) 
    { 
     if (!list.IsAlive) 
     { 
      count++; 
     } 
    } 

    if (count == listThreads.Count) 
    { 
     abort = false; 
    } 
} 

的問題是:

終止時的回報,我想追加masterList早些時候宣佈列表中的每個線程。

怎麼會這樣呢?

同時我知道必須有一個更好的辦法比下面等待所有線程完成

var abort = true; 
while (abort) //Wait until all threads finish 
{ 
    var count = 0; 
    foreach (var list in listThreads) 
    { 
     if (!list.IsAlive) 
     { 
      count++; 
     } 
    } 

    if (count == listThreads.Count) 
    { 
     abort = false; 
    } 
} 

回答

14

使用WaitHandle


這裏是一個例如:

using System; 
using System.Threading; 

class ThreadSleeper 
{ 
    int seconds; 
    AutoResetEvent napDone = new AutoResetEvent(false); 

    private ThreadSleeper(int seconds) 
    { 
     this.seconds = seconds; 
    } 

    public void Nap() 
    { 
     Console.WriteLine("Napping {0} seconds", seconds); 
     Thread.Sleep(seconds * 1000); 
     Console.WriteLine("{0} second nap finished", seconds); 
     napDone.Set(); 
    } 

    public static WaitHandle DoSleep(int seconds) 
    { 
     ThreadSleeper ts = new ThreadSleeper(seconds); 
     Thread thread = new Thread(new ThreadStart(ts.Nap)); 
     thread.Start(); 
     return(ts.napDone); 
    } 
} 

public class OperationsThreadsWaitingwithWaitHandle 
{ 
    public static void Main() 
    { 
     WaitHandle[] waits = new WaitHandle[2]; 
     waits[0] = ThreadSleeper.DoSleep(8); 
     waits[1] = ThreadSleeper.DoSleep(4); 

     Console.WriteLine("Waiting for threads to finish"); 
     WaitHandle.WaitAll(waits); 
     Console.WriteLine("Threads finished"); 
    } 
} 

個鏈接檢查出

+1

和我一樣的想法...但更好的方法回答:( – 2009-07-31 22:51:09

0

檢查出的WaitHandle類和WaitHandle.WaitAll的(我用的ManualResetEvent類中的一些我的WaitHandle的代碼,但它只是一個例子,我不知道你的情況是否有更好的東西)。關閉所有五個線程,給它們一個對主列表的引用,在添加到它時鎖定這個列表,然後發出信號完成。使用WaitHandle.WaitAll阻止所有五個信號完成。

2

最好的辦法是讓每個線程都是自己的對象。不要與其他對象混合,只需構造它(傳入變量),將自己添加爲偵聽器並啓動它。

完成後,它將值存儲在成員變量中並通知您的偵聽器。

您的聽衆可以在閒暇時檢索這些值。

明顯的快捷方式,直接返回值監聽,工作,但你可以更靈活後來發現這個版本(真的沒有太多的代碼)

1

您當然也可以使用常規代表以及APM

請注意,您描述的模式通常被描述爲一個Future,後者承諾稍後返回(如果可以,則爲投資回報)​​。

這是一個簡單的例子,以控制檯程序的形式。

輸出:

sequential: 3224 ms 
parallel: 2074 ms 

當然,因爲我沒有明確的建設線程,我讓線程池系統,以找出多少個線程並行運行。

還有規定,被告知,當後臺線程完成的,通過一個回調方法,以及WaitHandle的支持,明確檢查,並與超時等待,等

和源:

using System; 
using System.Collections.Generic; 
using System.Threading; 
using System.Diagnostics; 

namespace SO1215227 
{ 
    public class Program 
    { 
     public static void Main() 
     { 
      Stopwatch sw = new Stopwatch(); 
      sw.Start(); 
      var list1 = Sequence(1, 100); 
      var list2 = Sequence(101, 200); 
      var list3 = Sequence(201, 300); 
      sw.Stop(); 
      Console.Out.WriteLine("sequential: " + sw.ElapsedMilliseconds + " ms"); 
      sw.Reset(); 

      Func<Int32, Int32, List<Int32>> listProducer = Sequence; 
      sw.Start(); 
      var list1Background = listProducer.BeginInvoke(1, 100, null, null); 
      var list2Background = listProducer.BeginInvoke(101, 200, null, null); 
      var list3Background = listProducer.BeginInvoke(201, 300, null, null); 

      list1 = listProducer.EndInvoke(list1Background); 
      list2 = listProducer.EndInvoke(list2Background); 
      list3 = listProducer.EndInvoke(list3Background); 
      sw.Stop(); 
      Console.Out.WriteLine("parallel: " + sw.ElapsedMilliseconds + " ms"); 

      Console.Out.Write("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 

     private static List<Int32> Sequence(Int32 from, Int32 to) 
     { 
      List<Int32> result = new List<Int32>(); 
      for (Int32 index = from; index <= to; index++) 
      { 
       result.Add(index); 
       Thread.Sleep(10); // simulate I/O wait 
      } 
      return result; 
     } 
    } 
}