c# - 为什么我的 Windows 窗体卡住并死锁?

标签 c# winforms tpl-dataflow

对于我的生产者-消费者应用程序,我单击按钮来触发它。然而它卡住了。该项目的基本思想是在单击“开始”按钮时查找队列中有多少个偶数。单击“取消”按钮停止它。我想在控制台上打印结果。但两者都不起作用,这意味着没有输出(屏幕上为空)。可能会陷入僵局?不管怎样,屏幕卡住了。

整个干净的代码:

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 并传递取消 token 。

预期结果存储在变量evenNumber中。

最佳答案

您在单击按钮时阻塞了 UI,而您需要使用 .Waitawait

    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();
        }
    }

关于c# - 为什么我的 Windows 窗体卡住并死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26792642/

相关文章:

.net - TPL数据流和Akka.net有什么区别?

c# - 在 Xamarin Forms 中触发事件指示器

c# - 如何显式丢弃 out 参数?

c# - 如何从 DataGridView 中删除行?

c# - TPL 数据流,是否有 "WaitAny"的 block ?

c# - 如何使用委托(delegate)构建 TransformManyBlock

c# - System.Configuration.ConnectionStringSettingsCollection.this[string].get 返回 null

c# - 在 Roslyn 制作的编译中包含嵌入式资源

c# - 通过窗体传递值 C#

c++ - 关闭表单后启用按钮