如何在 Task.Delay 中退出 while 循环
How to get out a while loop when in Task.Delay
我试图在按下中止键时停止程序中的 while 循环,函数 运行ning 是 运行ning 一个 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);
}
当按下中止按钮时,我们将令牌设置为取消,我想退出 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) 但也不好。
而不是使用 Task.Delay
,您可以通过超时访问 WaitHandle
of the CancellationToken
and call WaitOne
。
如果令牌被取消,WaitOne
操作的 return 值将为 true
,如果达到超时,则为 false
,然后您可以从中获取适当的进一步行动。
我制作了一个小应用程序来展示我是如何让我的应用程序工作的。创建一个带有两个按钮的小型 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;
}
}
}
}
我试图在按下中止键时停止程序中的 while 循环,函数 运行ning 是 运行ning 一个 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);
}
当按下中止按钮时,我们将令牌设置为取消,我想退出 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) 但也不好。
而不是使用 Task.Delay
,您可以通过超时访问 WaitHandle
of the CancellationToken
and call WaitOne
。
如果令牌被取消,WaitOne
操作的 return 值将为 true
,如果达到超时,则为 false
,然后您可以从中获取适当的进一步行动。
我制作了一个小应用程序来展示我是如何让我的应用程序工作的。创建一个带有两个按钮的小型 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;
}
}
}
}