取消和处理 CancellationTokenSource 之间的延迟是否可以保证 IsCancellationRequested 将设置为 true?

如何解决取消和处理 CancellationTokenSource 之间的延迟是否可以保证 IsCancellationRequested 将设置为 true?

C# Windows UWP 项目

我已经在调用一个方法异步方法中实现了 CancellationTokenSource 和 CancellationToken。此方法包含一个 while 循环,该循环将 bool 变量的值保持为 true,直到令牌源被取消。

异步方法由鼠标左键按下事件触发,并由使用 ColorPicker 控件时发生的鼠标左键释放事件取消。 bool 变量允许在为真时将颜色值发送到设备,在为假时阻止它。

通过将该值保持为 true,只要鼠标按钮保持按下,设备就会在指针在颜色选择器周围移动时不断接收变化的颜色值。释放鼠标按钮后,产生的假值(由将颜色值发送到设备的例程设置)阻止进一步的颜色消息发送到设备。

我的代码也能满足我的要求,但我担心如果我没有正确实现它可能会产生潜在的副作用。我在这个论坛上至少看到一个帖子,表明序列:cancel、dispose 和 set to null 可用于 CancellationTokenSource。但让我担心的是,我有一个潜在的无限 while 循环,它完全取决于接收取消令牌。所以我的问题是过早处理 CancellationTokenSource 是否会阻止 token.IsCanellationRequested 被设置为 true,如果是这样,添加延迟会增加任何好处吗?

以下是我的代码中的相关片段:

全局变量

public static bool colorPickerPtrpressed = false;
static CancellationTokenSource cts = null;
static CancellationToken token;

鼠标按钮事件:

private void ColorPicker_PtrpressedEvent(object sender,PointerRoutedEventArgs e)
{
    if(cts == null) cts = new CancellationTokenSource();
    token = cts.Token;

    var picker = sender as ColorPicker.ColorPicker;

    colorPickerPtrpressed = true;
    (picker.DataContext as Spheroviewmodel).Color = picker.SelectedColor.Color;

    ColorChange(token);

}

private void ColorPicker_PtrReleasedEvent(object sender,PointerRoutedEventArgs e)
{
    if (cts != null)
    {
        cts.Cancel();
        Task.Delay(500).Wait(); // Allow some time for cancel to take effect
        cts.dispose();
        cts = null;
    } 
}

取消令牌方法

public static async Task ColorChange(CancellationToken token)
{
    await Task.Run(() =>
    AllowColorChange(token),token);
}

public static void AllowColorChange(CancellationToken token)
{
        while (!token.IsCancellationRequested)
        {
            colorPickerPtrpressed = true; // Maintain value as true
            Task.Delay(100).Wait(); // allow color updates periodically
        }
    return;
}

解决方法

所以我的问题是,在取消和处理 CancellationTokenSource 之间是否有延迟,正如我在下面的“ColorPicker_PtrReleasedEvent”中所做的那样,是否可以保证 while 循环将终止?

没有。取消模型是合作的,调用 Cancel 只是通过将所有令牌的 IsCancellationRequested 属性设置为 true 来提供取消的通知

然后由任何可取消的 API(即接受 CancellationToken 的任何方法)来监视此属性的值并响应取消请求。

所以 ColorPicker_PtrReleasedEvent 不能保证 while 循环会在 AllowColorChange 处终止。

,

按照 TZ 的建议,我修改了最后三个方法以等待来自 AllowColorChange(token) 方法的取消标志,然后使用该结果作为对 CancellationTokenResult 的 dispose() 的许可,并将其设置为 null。如果有人发现我所做的有问题,请告诉我。以下是修改后的代码,看起来运行良好:

    private void ColorPicker_PntrReleasedEvent(object sender,PointerRoutedEventArgs e)
    {
        if (cts != null)
        {
            cts.Cancel();
            //Task.Delay(200).Wait(); // Allow some time for cancel to take effect
            //cts.Dispose();
            //cts = null;
        }
    }

    public static async Task ColorChange(CancellationToken token)
    {
        bool task = false;
        task = await Task.Run<bool>(() =>
        AllowColorChange(token),token);
        if (task)
        {
            cts.Dispose();
            cts = null;
        }
        else
        {
            // Shouldn't ever reach this point
            bool isBrkPnt = true;
        }
    }

    public static async Task<bool> AllowColorChange(CancellationToken token)
    {
            while (!token.IsCancellationRequested)
            {
                colorPickerPtrPressed = true; // Maintain value as true
                await Task.Delay(100); // allow color updates periodically
            }
        return true; // signal that task was canceled
    }

}
,

在实施 Theodor Zoulias 提出的建议后,最终代码如下所示。可以看出,在取消和处理 CancellationTokenSource 之间没有使用任意延迟,而是将处理移动到 catch{} 块,该块由抛出 token.ThrowIfCancellationRequested(); 导致的 OperationCanceledException 触发;在 while() 循环中,它被移动到 try{} 块中,并且它的测试参数设置为 true。不再需要测试 token.IsCancellationRequested 的值作为 while 循环的参数。此编码可确保在取消 try{} 块内的任务之前不会发生处置。

     private void ColorPicker_PntrPressedEvent(object sender,PointerRoutedEventArgs e)
    {
        if(cts == null) cts = new CancellationTokenSource();
        token = cts.Token;

        var picker = sender as ColorPicker.ColorPicker;

        colorPickerPtrPressed = true; // True allows new values of color to be sent to device
        (picker.DataContext as SpheroViewModel).Color = picker.SelectedColor.Color;

        ColorChange(token); // Don't await this

    }

    private void ColorPicker_PntrReleasedEvent(object sender,PointerRoutedEventArgs e)
    {
        if (cts != null)
        {
            cts.Cancel();
        }
    }

    public static async Task ColorChange(CancellationToken token)
    {
        try
        {
            await Task.Run(async () =>
            {
                while (true)
                {
                    token.ThrowIfCancellationRequested();
                    colorPickerPtrPressed = true; // Maintain value as true while mouse button remains pressed
                    await Task.Delay(100,token); // allow color updates periodically
                }
            },token);
        }
        catch (OperationCanceledException ex) when (ex.CancellationToken == token) // includes TaskCanceledException
        {
            if (cts != null) // Shouldn't arrive here if it is null but check just in case
            {
                try
                {
                    cts.Dispose();
                    cts = null;
                }
                catch (ObjectDisposedException e)
                {
                    // Already disposed,do nothing
                    bool brkPnt = true;
                }
            }
        }
    }

}

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?