2012-10-15 63 views
4

我需要凍結主線程直到結束遞歸。 遞歸深度=線程數。如何跟蹤所有線程的完成情況。 C#

示例代碼:

BackgroundWorker backgroundWorker1; 
    Random ran; 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     method(); 
     label1.Text = "Threads is finished"; 
    } 


    private void method() // recursive method 
    { 

      Thread.Sleep(100); 

      backgroundWorker1 = new BackgroundWorker(); 

      backgroundWorker1.DoWork += 
       new DoWorkEventHandler(backgroundWorker1_DoWork); 
      backgroundWorker1.RunWorkerAsync();    //Beginning new thread 
    } 

    private void backgroundWorker1_DoWork(object sender, 
     DoWorkEventArgs e) 
    { 
      ran = new Random(); 
      Thread.Sleep(ran.Next(500, 1000)); 
      if (ran.Next(1, 5) != 1) // if = 1 then to stop recursion 
      { 
       method(); 
      } 
    } 

當線程完成時,label1.Text必須具有值"Threads is finished"。這是如何完成的?

+0

您分配一個新的「線程/工作者」對象實例的現有的和單'backgroundWorker1'變量,不知道這是好的,至少如果你想wairing所有創建的線程,這不是很好,你有以引用所有創建的線程/工作者實例 – sll

+1

我相信這種模式被稱爲叉式炸彈,但它不能很好地擴展。同樣如sll指出的那樣,這些實例變量不是線程安全的。爲什麼不問問題而不是提出一個解決方案? http://blogs.msdn.com/b/oldnewthing/archive/2006/03/23/558887.aspx –

+1

代碼太愚蠢了,重複啓動bgw沒有意義。只需使用一個bgw並在DoWork中編寫一個循環。在RunWorkerCompleted事件處理程序中設置標籤。 –

回答

1

控制檯應用程序PoC緩存對所有創建的工作人員的引用,並使用數字變量檢查有多少工人仍在進行中,當此值達到0時 - 應用程序終止。如有任何問題,請通知我。

class Program 
{ 
    private static IList<BackgroundWorker> workers; 
    private static Random ran; 
    private static int activeWorkersCount; 

    static void Main(string[] args) 
    {    
     workers = new List<BackgroundWorker>(); 
     DoWork(); 

     while (activeWorkersCount > 0) 
     { 
      Thread.Sleep(200); 
     } 

     Console.WriteLine("Waiting for all workers to finish..."); 
     Console.ReadLine(); 
    } 

    private static void DoWork() // recursive method 
    { 
     Thread.Sleep(100); 

     var newWorker = new BackgroundWorker(); 

     newWorker.DoWork += BackgroundWorkerDoWork; 
     newWorker.RunWorkerCompleted += (o, e) => 
       { 
        Console.WriteLine("[E] Worker finished"); 
        Interlocked.Decrement(ref activeWorkersCount); 
       }; 
     Interlocked.Increment(ref activeWorkersCount); 
     newWorker.RunWorkerAsync(); 
    } 

    private static void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e) 
    { 
     Console.WriteLine("[S] Worker started"); 
     ran = new Random(); 
     Thread.Sleep(ran.Next(500, 1000)); 
     if (ran.Next(1, 5) != 1) // if = 1 then to stop recursion 
     { 
      DoWork(); 
     } 
    } 
} 
+0

我這樣做過。 while(activeWorkersCount> 0) { Thread.Sleep(200); } 第一個線程完成後返回false。 在這個問題... 用自己的語言說話,如果你會很舒服。我是俄羅斯人 – saj113

+0

那麼有些事情不符合你的預期?請描述 – sll

+0

是的,創建一個線程可以是幾十個。當完成所有線程時,我需要得到消息 – saj113

0

當您決定是時候停止遞歸時,您可以在GUI線程上發佈回調。關閉我的頭頂,它會是這樣的:

if(ran.Next(1,5)!=1) 
{ 
    method(); 
} 
else 
{ 
    Action action=()=>label1.Text = "Threads is finished"; 
    this.BeginInvoke(action); 
} 
0

1)創建,更新Label1的方法:

private void WorkFinished() 
{ 
    if(Label1.InvokeRequired) 
    { 
     Label1.Invoke(WorkFinished); 
    } 
    else 
    { 
     Label1.Text = "Threads is finished"; 
    } 
} 

2)請從backgroundWorker1_DoWork WorkFinished()。

0

您可以使用CountDownEvent類:

例子:

using (CountDownEvent countdownEvent = new CountdownEvent(numberOfThreads)) 
{ 
    for (int threadIndex= 0; i < numberOfThreads; threadIndex++) 
     ThreadPool.QueueUserWorkItem(
      th => 
      { 
       DoWork(); 
       countdownEvent.Signal(); 
      }, threadIndex); 

    countdownEvent.Wait(); 
} 
Console.WriteLine("All threads complete"); 
+1

控制檯應用程序'CountDownEvent'不適合這個解決方案,我相信'numberOfThreads'是未知的,在運行時可以改變sicne這取決於下一個隨機產生價值,所以每個線程ENW將調用'隨機()',它可能是一個新的線程將被安排,所以你需要增加'numberOfThreads',這是不可能的'CDE' – sll

+1

CountDownEvent似乎支持添加爲好,只要計數沒有達到0(導致事件被設置)。 [CountDownEvent.AddCount](http://msdn.microsoft.com/en-us/library/dd321903.aspx) –

+0

@ChrisChilvers:謝謝,有道理。我已經忽略了這一點,道歉 – sll

0

我做到了使用揮發性整數,而且運作良好。

BackgroundWorker backgroundWorker1;  
    Random ran; 
    long runningThreads = 0; 
    public void Start()  
    {   
     method();   
     // Console.WriteLine("Threads is finished");  
    }  
    private void method() // recursive method  
    { 
     Interlocked.Increment(ref runningThreads); 
     Console.WriteLine("New thread started"); 
     Thread.Sleep(100);    
     backgroundWorker1 = new BackgroundWorker();    
     backgroundWorker1.DoWork +=     
      new DoWorkEventHandler(backgroundWorker1_DoWork);    
     backgroundWorker1.RunWorkerAsync();    //Beginning new thread  
    }  
    private void backgroundWorker1_DoWork(object sender,  DoWorkEventArgs e)  
    {    
     ran = new Random();    
     Thread.Sleep(ran.Next(500, 1000));    
     if (ran.Next(1, 5) != 1) // if = 1 then to stop recursion    
     {     
      method();    
     } 
     Finished(); 
    } 
    private void Finished() 
    { 
     Interlocked.Decrement(ref runningThreads); 
     if (Interlocked.Read(ref runningThreads) == 0) 
     { 
      Console.WriteLine("Threads is finished");  

     } 
    } 
+0

可能會導致檢查if(runningThreads == 0)在incrementThreads ++增量之前的情況。由於你沒有使用鎖? – Ngm

+0

這就是爲什麼我已經採取揮發性INT –

+1

volatile關鍵字將確保你不讀從緩存中的變量,但它保證避免這裏的競爭條件?例如檢查以下步驟:1.減少正在運行的線程2檢查正在運行的線程== 0並在控制檯語句3之前:另一個線程正在執行並增加runningThreads,正確嗎?那是使用互鎖增量,互鎖遞減和CountDownEvent的原因嗎? – Ngm

相關問題