【问题标题】:How to get out a while loop when in Task.Delay在Task.Delay中如何退出while循环
【发布时间】:2022-01-25 09:33:31
【问题描述】:

我试图在按下中止键时停止程序中的 while 循环,并且正在运行的函数正在运行 Task.Delay。不幸的是,即使这必须很容易做到,我也无法让它为我工作。请帮忙。

我有一个按钮,要求用户确认他们想要运行,如果是,它会进入下面的函数并开始运行 RunSequence 函数。我确实在一个新线程上有这个,但现在已经将它更改为一个任务,我留下注释掉的代码以防万一我需要运行它而不是任务。 RunSequence 有两个参数,第二个是我认为我应该有的,那就是 CancellationToken。

CancellationTokenSource tokenSource = new CancellationTokenSource();

    private void ConfirmRunSequence()
    {
    //put it on a thread as the UI is slow to update
    //var thread = new Thread(() => { RunSequence(_filePathName, tokenSource.Token); });
    //thread.IsBackground = true;
    //thread.Start();
    
    Task.Run(() => RunSequence(_filePathName, tokenSource.Token), tokenSource.Token);
    }

当按下中止按钮时,我们将 Token 设置为取消,我想退出 While 循环。

private void onAbort()
{
Abort = true; //set to abort sequence
            tokenSource.Cancel();
}

我希望上面的部分是正确的,我认为下一点是我不明白的。在这里,我有一个名为 _ct 的 CancellationToken,我认为它是 tokenSource。我在这里的延迟很大,所以当我看到标签更新几次时,我会点击中止,它会在我想取消的延迟之内。现在这是我无法开始工作的地方。

我在 _ct 下看到一个红色的波浪线,上面写着“无法从 System.Threading.CancellationToken 转换为 System.Threading.Task.Task”。好的,我阅读了这些文字,但抱歉我不知道如何修复它,但我也不知道我是否修复了它,如果这是退出 While 循环的正确方法,请帮助。

private async void RunSequence(string filePath, CancellationToken _ct)
{
    Int count = 0;

while (!sr.EndOfStream) 
{
    lbl_count = count++;
    await Task.WhenAny(Task.Delay(10000), _ct);
}

lbl_count =”aborted”;
}

我尝试过的事情之一是从 await Task.WhenAny(Task.Delay(10000), _ct);至 只是 Task.Delay(10000, _ct) 也不好。

【问题讨论】:

  • 只需在 while 循环中使用 ct.ThrowIfCancellationRequested()
  • 不要使用新线程。有任务时就不需要了。
  • 请出示您的真实密码。除非lbl_countobject,否则您不能拥有lbl_count = count++;lbl_count =”aborted”;

标签: c# while-loop task abort


【解决方案1】:

您可以访问CancellationTokenWaitHandle,而不是使用Task.Delay,并在其上调用WaitOne,通过超时。

如果令牌被取消,WaitOne 操作的返回值将为true,如果达到超时,则为false,然后您可以从中采取适当的进一步操作。

【讨论】:

    【解决方案2】:

    我制作了一个小应用程序来展示我是如何让我的应用程序工作的。创建一个带有两个按钮的小型 C# Winform .Net,一个用于运行,一个用于中止和一个标签。由于有代码请求,我在 Github 上包含了完整的示例程序

    https://github.com/zizwiz/Cancellation_Token_Example

    我还在下面添加了一些代码的副本:

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace Cancel_Token_Example
    {
        public partial class Form1 : Form
        {
    
            CancellationTokenSource tokenSource; // Declare the cancellation token
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void btn_run_Click(object sender, EventArgs e)
            {
                tokenSource = new CancellationTokenSource();    //Make a new instance
                Task.Run(() => RunSequence(tokenSource.Token)); //Run the task that we need to stop
            }
    
            private void btn_abort_Click(object sender, EventArgs e)
            {
                tokenSource.Cancel(); // make the token a cancel token
            }
    
            private async void RunSequence(CancellationToken _ct)
            {
                int counter = 0;
    
                while (!_ct.IsCancellationRequested)
                {
                    // show incrementing number but as we have a task watch for cross threading
                    WriteUIData((counter++).ToString());
    
                    try
                    {
                        await Task.Delay(1000, _ct); //waits 1 second
                    }
                    catch
                    {
                        // Do nothing just needed so we can exit without exceptions
                    }
    
                }
    
                if (_ct.IsCancellationRequested)
                {
                    //report we have cancelled
                    WriteUIData("Cancelled");
                }
    
                tokenSource.Dispose(); //dispose of the token so we can reuse
            }
    
            private void WriteUIData(String data)
            {
                // Write data to UI but as we have a task watch for cross threading
    
                if (lbl_output.InvokeRequired)
                {
                    lbl_output.BeginInvoke((MethodInvoker)delegate () { lbl_output.Text = data; });
                }
                else
                {
                    lbl_output.Text = data;
                }
            }
        }
    }
    

    【讨论】:

    • 感谢您向大家表示感谢,但本网站以高质量、简洁的问题和答案而自豪。我已将您的答案编辑为这样。不过,请随时感谢 cmets 中的每个人。
    猜你喜欢
    • 1970-01-01
    • 2011-12-18
    • 2015-01-18
    • 2023-04-08
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    • 2022-01-26
    • 2014-11-28
    相关资源
    最近更新 更多