2014-11-07 30 views
0

對於我的生產者 - 消費者應用程序,我點擊了按鈕來觸發它。但它凍結。該項目的基本思想是在單擊「開始」按鈕時查找隊列中有多少個偶數。點擊取消按鈕停止它。我想在控制檯上打印結果。但兩者都不工作,這意味着沒有輸出(在屏幕上爲空)。它可能是僵局?無論如何,屏幕凍結。爲什麼我的窗口凍結和死鎖?

整個清潔代碼:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Threading.Tasks.Dataflow; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace CancellationTokenStop 
{ 
    public partial class Form1 : Form 
    { 
     public static BufferBlock<int> m_Queue = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1000 }); 
     private static int evenNumber; 
     private static CancellationTokenSource cTokenSource; 
     private static CancellationToken cToken; 
     private static Object obj = new object(); 
     [DllImport("kernel32.dll", SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     static extern bool AllocConsole(); 
     public Form1() 
     { 
      InitializeComponent(); 
      AllocConsole(); 
     } 

     private void btnCancel_Click(object sender, EventArgs e) 
     { 
      cTokenSource.Cancel(); 
     } 

     private void btnStart_Click(object sender, EventArgs e) 
     { 
      try 
      { 
       cTokenSource = new CancellationTokenSource(); 
       cToken = cTokenSource.Token; 
       var producer = Producer(); 
       var consumer = Consumer(); 

       Task.WhenAll(producer, consumer).Wait(); 
       Report(); 
      } 
      catch (AggregateException ex) 
      { 
       Console.WriteLine(ex.InnerException); 
       Console.Read(); 
      } 
     } 

     static async Task Producer() 
     { 
      for (int i = 0; i < 200; i++) 
      { 
       // Send a value to the consumer and wait for the value to be processed 
       await m_Queue.SendAsync(i); 
      } 
      // Signal the consumer that there will be no more values 
      m_Queue.Complete(); 
     } 

     static async Task Consumer() 
     { 
      try 
      { 
       var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions 
       { 
        MaxDegreeOfParallelism = 4 
       }; 
       var consumerBlock = new ActionBlock<int>(x => 
       { 
        DoWork(x, cToken); 
        if (x % 2 == 0) 
         // Increment the counter in a thread-safe way 
         Interlocked.Increment(ref evenNumber); 

       }, executionDataflowBlockOptions); 

       // Link the buffer to the consumer 
       using (m_Queue.LinkTo(consumerBlock, new DataflowLinkOptions { PropagateCompletion = true })) 
       { 
        // Wait for the consumer to finish. 
        // This method will exit after all the data from the buffer was processed. 
        await consumerBlock.Completion; 
       } 
      } 
      catch (OperationCanceledException ex) 
      { 
       Console.WriteLine(ex.Message); 
       Console.Read(); 
      } 
     } 

     static void DoWork(int x, CancellationToken cToken) 
     { 
      cToken.Register(() => 
      { 
       Console.WriteLine("Stop at "+x); 
      }); 
      Thread.Sleep(100); 
     } 

     public static void Report() 
     { 
      Console.WriteLine("There are {0} even numbers", evenNumber); 
     } 
    } 
} 

生產者部分是簡單的,它只是將數據發送到BufferBlock。消費者部分很複雜,使用ActionBlock並傳遞取消令牌。

預期結果存儲在變量evenNumber中。

+0

「凍結」或GUI應用程序「死鎖」幾乎總是意味着你已經封鎖在程序主線程,處理所有的繪圖和用戶輸入的一個。如果你真的搜索網頁或StackOverflow,你會發現很多關於這個主題的討論,以及很好的解決方案。 – 2014-11-07 01:45:23

+0

那麼,因爲你特別說它應該等待()。 Task.WhenAll(生產者,消費者).Wait();阻止你的用戶界面,更好,如果你應該等待生產者和消費者的呼籲 – DevEstacion 2014-11-07 02:27:11

+0

看看http://stackoverflow.com/questions/19766535/task-waitall-not-working-as-expected – cost 2014-11-07 02:39:39

回答

0

您正在屏蔽您的用戶界面,請點擊.Wait您需要改爲await

private async void btnStart_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      cTokenSource = new CancellationTokenSource(); 
      cToken = cTokenSource.Token; 
      var producer = Producer(); 
      var consumer = Consumer(); 

      await Task.WhenAll(producer, consumer); 
      Report(); 
     } 
     catch (AggregateException ex) 
     { 
      Console.WriteLine(ex.InnerException); 
      Console.Read(); 
     } 
    }