2010-08-27 130 views
3

創建我的線程數多線程工作線程狀態

for (int i = 0; i < threadCount; i++) 
{ 
    Searcher src = new Searcher(i, this); 

    threads[i] = new Thread(new ThreadStart(src.getIpRange)); 
    threads[i].Name = string.Format(i.ToString()); 
    } 

    foreach (Thread t in threads) 
    { 
    t.Start(); 
    } 

與經緯(= 100,150,255等...),但我不能學多少線程工作。執行時間。

我想要控制所有線程何時完成其工作。並給我一個消息,如「所有線程都死了,作業已完成...」 像backgroundWorker的RunWorkerCompleted事件

+0

我很難想象一個應用程序,其中255個相同的線程是最優的。請記住,在任何給定時間可以運行系統的最大線程數=目標硬件中獨立CPU內核的數量。 fwiw這是我的經驗(Win XP SP2),在單個進程中大約120次後線程創建失敗。這是在每個基於套接字的應用程序客戶端使用一個線程實現的測試應用程序中。沒辦法,我會以這種方式實現實際的生產代碼。 – 2010-08-30 17:18:53

+0

我正在研究網絡應用程序,所以我的線程花費了很多時間。和我這是不是一個超載的CPU – Rapunzo 2010-09-03 15:05:57

回答

0

爲什麼不能使用臨界區保護單變量來控制多個活動線程?線程函數可以修改這個變量(當然已經進入臨界區)。

+0

你可以擴大什麼是「關鍵部分受保護的單一變量」?以及如何使用 – Rapunzo 2010-08-27 14:44:18

+0

以下是一些示例和定義:http://en.wikipedia.org/wiki/Critical_section – 2010-08-28 13:32:10

1

確定所有線程何時完成都很簡單。

for (int i = 0; i < threadCount; i++) 
{ 
    threads[i].Join(); 
} 

Console.WriteLine("All threads are done!"); 

您能詳細說明您的其他要求嗎?

+0

我嘗試了這一點,但阻止了進度。 – Rapunzo 2010-08-27 12:32:20

+0

@Rununzo - 的確,這就是要點。 'Thread.Join'是一個阻塞調用 - 因此'Console.WriteLine'將不會執行,直到所有線程完成。您可以在另一個線程上運行這段代碼,並根據您選擇的通知機制進行適當的同步。爲了簡單起見,我在這裏使用了'Console.WriteLine'。 – 2010-08-27 14:10:27

1

您可以檢查線程的ThreadState屬性。

可能會更好地使用異步方法。這會爲您提供一個WaitHandle對象,並且您可以使用WaitHandle.WaitAll等待所有異步方法完成。

這裏有一個介紹到異步編程: http://msdn.microsoft.com/en-us/library/aa719598%28v=VS.71%29.aspx

+0

你能解釋一下異步方法嗎? – Rapunzo 2010-08-27 12:33:47

+0

您使用BeginInvoke()調用方法而不是直接調用它 – Jerome 2010-08-27 13:00:22

1

首先,我要指出的是創造100,150,255,等線程可能不是一個好主意。使用ThreadPoolTask類(如果使用.NET 4.0)可能會更好。除此之外,還有兩種完善的方法用於等待所有線程完成。

加入該主題。

Thread.Join塊直到目標線程結束。

for (int i = 0; i < threadCount; i++) 
{ 
    Searcher src = new Searcher(i, this); 
    threads[i] = new Thread(new ThreadStart(src.getIpRange)); 
    threads[i].Name = string.Format(i.ToString()); 
} 

foreach (Thread t in threads) 
{ 
    t.Start(); 
} 

foreach (Thread t in threads) 
{ 
    t.Join(); 
} 

使用CountdownEvent。

A CountdownEvent等待其內部計數達到零。如果您想使用ThreadPool,此方法更適合。如果你不使用.NET 4.0,你可以通過Joe Albahari's website獲得一個非常簡單的實現。

var finished = new CountdownEvent(1); 

for (int i = 0; i < threadCount; i++) 
{ 
    finished.AddCount(); 
    Searcher src = new Searcher(i, this); 
    threads[i] = new Thread(
    () => 
    { 
     try 
     { 
      src.getIpRange(); 
     } 
     finally 
     { 
      finished.Signal(); 
     } 
    } 
    threads[i].Name = string.Format(i.ToString()); 
} 

foreach (Thread t in threads) 
{ 
    t.Start(); 
} 

finished.Signal(); 
finished.WaitOne(); 
+0

是在.net 3.5中定義的countdownevent? – Rapunzo 2010-08-27 14:22:03

+0

不,我更新了我的答案,包含一個簡單實現的鏈接。 – 2010-08-27 14:35:22

1

你一定要使用Task類本或類似Parallel.ForEach更高層次的概念。直接使用Thread類非常痛苦。

我最近wrote a blog post比較各種異步方法,按從最佳(Task)到最差(Thread)的順序列出。

下面是一個使用Task一個例子,證明你想要做什麼:

// Start all tasks 
var threads = new Task[threadCount]; 
for (int i = 0; i < threadCount; i++) 
{ 
    Searcher src = new Searcher(i, this); 
    threads[i] = Task.Factory.StartNew(src.getIpRange); 
} 

// How many are running right now? 
var runningCount = threads.Count(x => x.Status == TaskStatus.Running); 

// Register a callback when they have all completed (this does not block) 
Task.Factory.ContinueWhenAll(threads, MyCallback); 
+0

我嘗試添加使用System.Threading.Tasks;到我的項目,但得到一個錯誤:名稱空間'System.Threading'中不存在類型或命名空間名稱'Tasks'(您是否缺少程序集引用?) – Rapunzo 2010-08-27 14:05:27

+0

要使用Task類,您需要.NET 4.0或用於.NET 3.5的[Rx庫](http://msdn.microsoft.com/zh-cn/devlabs/ee794896.aspx)。 – 2010-08-27 15:10:43

1

添加了代表對搜索器,並從你的主線程傳遞一個回調方法,當它完成每個線程將調用。在啓動每個線程時,將其添加到由線程的ManagedThreadId鍵入的字典中。當每個線程完成時,回調會從Dictionary中刪除該線程,並檢查計數是否爲零。

 Dictionary<int, Thread> activeThreads = new Dictionary<int, Thread>();    

      for (int i = 0; i < threadCount; i++) 
      { 
       Searcher src = new Searcher(i, this); 
       src.Done = new SearcherDoneDelegate(ThreadDone); 
       threads[i] = new Thread(new ThreadStart(src.getIpRange)); 
       threads[i].Name = string.Format(i.ToString()); 
      } 

      foreach (Thread t in threads) 
      { 
       lock (activeThreads) 
       { 
        activeThreads.Add(t.ManagedThreadId, t); 
       } 
       t.Start(); 
      } 


     } 
     public void ThreadDone(int threadIdArg) 
     { 
      lock (activeThreads) 
      { 
       activeThreads.Remove(threadIdArg); 
       if (activeThreads.Count == 0) 
       { 
        // all done 
       } 
      } 
     } 

     public delegate void SearcherDoneDelegate(int threadIdArg); 
     public static object locker = new object(); 



     public class Searcher 
     { 
      public SearcherDoneDelegate Done { get; set; } 
      public void getIpRange() 
      { 
       Done(Thread.CurrentThread.ManagedThreadId); 
      } 
     } 

如果你有多個線程比你想在同一時間運行,把它們放入一個隊列,並剝離掉相應的舊的線程結束(使用回調)。

+0

感謝您的解決方案,但(activeThreads.Count == 0)不工作healty,很多次失敗! 這裏是我的代碼 如果((activeThreads.Count)== 0){ J ++; progressBar1.Value = 0; btnSearch.Enabled = true; } 在這種情況下progressbar1。價值獲得0和多次成長後,再次開始0。我不能確定線程已經完成 – Rapunzo 2010-09-03 15:02:08

+0

@Rapunzo - 發生的事情是,一旦創建了每個線程,就開始創建每個線程,並且在後面的線程開始之前初始線程已經完成。解決這個問題的快速方法是將t.Start()移動到第二個循環,以便在啓動它們之前創建它們。更優雅的方法是將創建的線程放在隊列中,並使用生產者 - 消費者模式讀取它們。這也可以讓你控制併發線程的數量。 – 2010-09-03 17:35:35