这种在关闭端口之前使用任务取消的方法是否正确?

Is this way of using Task cancellation before closing port correct?

我有一个 C# GUI 应用程序,当单击按钮然后 MyMethod 启动时 运行 异步方式,它连续(在 do while 循环内)调用 MyTask。 MyTask 从端口写入和读取数据。并将这些数据传递给 MyProgressMethod 以进行进一步处理。

我想实现一个按钮,它首先 cancel/stop MyTask 然后关闭端口。

作为异步方式的新手,我依赖于一些我偶然发现的在线示例,其余的则难以掌握。根据我阅读的内容,我想出了以下方法来通过按钮实现取消。但是我不是很明白这个机制,想知道下面的方式是否正确:

在 class 的开头声明 CancellationTokenSource 对象:

CancellationTokenSource my_cancelationTokenSource = null;

按钮点击事件。按钮事件调用 MyMethod:

 private void Button_Click(object sender, RoutedEventArgs e)
 {
    //Some code
    MyMethod();
 }

MyMethod 每秒调用 MyTask 并将数据传递给 MyProgressMethod:

private async void MyMethod()
{

    my_cancelationTokenSource = new CancellationTokenSource();

    do
        {
            await Task.Delay(1000);
            //Process some code
            byte[] my_received_data = await MyTask(my_sent_data, my_cancelationTokenSource.Token);
            MyProgressMethod(my_received_data, my_sent_data);
        }
        while (true);
}

MyTask读写端口(关闭端口前需要取消):

private async Task<byte[]> MyTask(byte[] my_sent_data, CancellationToken cancelToken)
{

    await Task.Delay(200, cancelToken);//??? What should happen here?
    //Some code
    
}

取消任务关闭端口的按钮事件:

private  void Button_Disconnect_Click(object sender, RoutedEventArgs e)
{

    my_cancelationTokenSource.Cancel();

    if (my_port.IsOpen)
    {
        my_port.Close();
    }

}

如何优化此代码的稳定性?(即端口应仅在任务取消后关闭)

这里的解决方法是不要直接从Disconnect按钮关闭端口。相反,取消令牌,并在 MyMethod:

中捕获 OperationCanceledException
private CancellationTokenSource my_cancelationTokenSource;

private async void MyMethod()
{
    my_cancelationTokenSource = new CancellationTokenSource();
    try
    {
        while (true)
        {
            await Task.Delay(1000, my_cancelationTokenSource.Token);
            //Process some code
            byte[] my_received_data = await MyTask(my_sent_data, my_cancelationTokenSource.Token);
            MyProgressMethod(my_received_data, my_sent_data);
        }
    }
    catch (OperationCanceledException)
    {
        try
        {
            my_cancelationTokenSource.Dispose();
            my_cancelationTokenSource = null;
            my_port.Dispose();
        }
        catch {  }
    }
}

private void Button_Disconnect_Click(object sender, RoutedEventArgs e)
{
    my_cancelationTokenSource?.Cancel();
}

备注:

  • my_cancelationTokenSource 成为字段而不是局部变量。
  • 也将令牌传递给 Task.Delay 函数。 (目前还不清楚为什么你需要延迟,通常你只是等待端口上的响应)。
  • 我不知道你到底想在取消时做什么,我会留给你。
  • try/catch 关闭端口,您应该通过 Dispose 关闭端口,以防它抛出。