简体   繁体   English

退出异步无限循环

[英]Exiting from async infinite loops

I have initiated some async infinite loops in my WinForm application, but each time I am trying to break out of them, the program hangs up. 我在WinForm应用程序中启动了一些异步无限循环,但每次我试图突破它们时,程序都会挂起。 I have read some similar topics where people suggested using CancellationTokens, but I am not able to adapt them to my needs. 我已经阅读了一些人们建议使用CancellationTokens的类似主题,但我无法根据自己的需要调整它们。 Here is the relevant part of my code. 这是我的代码的相关部分。

static bool processStop = false;
static bool processStopped = false;

//Called once 
private async void ProcessData()
{
    while (!processStop)
    {
        await Task.Run
        (
            () =>
            {
                //Do stuff and call regular not async methods
            }
        );
    }
    processStopped = true;
}

//Button click handler to exit WinForm
btnExit.Click += (senders, args) =>
{
    processStop = true;
    //Programm hangs up here

    while (!processStopped);

    FormMain.Close();                
}

Edited the code 编辑了代码
The variables are static. 变量是静态的。
The Close method is the default Close() method for Forms. Close方法是Forms的默认Close()方法。

The problem is that the call to Task.Run continues on the main thread. 问题是对主线程的Task.Run调用继续。 processStop = true; and while (!processStopped); while (!processStopped); execute synchronously one after the other. 一个接一个地同步执行。 This doesn't let the ProcessData method continue its execution and a deadlock occures. 这不会让ProcessData方法继续执行并发生死锁。
I see a couple of solutions: 我看到了几个解决方案:

  • Use ConfigureAwait(false) with Task.Run : Task.Run使用ConfigureAwait(false)

     private async void ProcessData() { while (!processStop) { await Task.Run ( () => { //Do stuff and call regular not async methods } ).ConfigureAwait(false); } processStopped = true; } 

    This will cause the ProcessData to continue on a thread pool and you already use a thread pool by calling Task.Run , so it is not a great solution 这将导致ProcessData在线程池上继续,并且您已经通过调用Task.Run使用线程池,因此它不是一个很好的解决方案

  • Wrap the whole process in Task.Run : Task.Run包装整个过程:

     static volatile bool processStop = false; static volatile bool processStopped = false; //Called once private async void ProcessData() { await Task.Run(() => { while (!processStop) { ... } processStopped = true; }); } 

    This would require changing the form of the method passed to work with the loop in it. 这将需要更改传递的方法的形式以使用其中的循环。

  • Make ProcessData a synchronous method to process CPU-intensive tasks and call it properly. 使ProcessData成为处理CPU密集型任务并正确调用它的同步方法。 CancellationToken would be the preferred way to cancel the task: CancellationToken将是取消任务的首选方式:

     private void ProcessData(CancellationToken token) { while(!token.IsCancellationRequested) { // do work } } 

    And call it with this: 并称之为:

     Task processingTask; CancellationTokenSource cts; void StartProcessing() { cts = new CancellationTokenSource(); processingTask = Task.Run(() => ProcessData(cts.Token), cts.Token); } btnExit.Click += async (senders, args) => { cts.Cancel(); try { await processingTask; } finally { FormMain.Close(); } } 

If you want to spin a bunch of tasks without blocking you can do this: 如果你想在不阻塞的情况下旋转一堆任务,你可以这样做:

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //Called once 
        private async Task ProcessData()
        {
            int count = 0;
            while (true)
            {
                await Task.Run
                 (
                     () =>
                     {
                         this.Invoke(new Action(() => {
                             label2.Text = (count++).ToString();
                             label1.Text = DateTime.Now.ToString(); }));
                         Thread.Sleep(100);
                     }
                 );
            }
            Debugger.Break(); //you will never see this hit at all
        }
        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private async void button2_Click(object sender, EventArgs e)
        {
           await ProcessData();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM