C# 对任务使用CancellationToken。运行

C# 对任务使用CancellationToken。运行,c#,task,cancellationtokensource,C#,Task,Cancellationtokensource,我有一些使用任务的代码。使用取消令牌运行 这是我的密码: public class TaskObject { CancellationTokenSource _source = new CancellationTokenSource(); public async Task TaskAction() { var task = Task.Run(async delegate { await TaskRun();

我有一些使用
任务的代码。使用取消令牌运行

这是我的密码:

public class TaskObject
{
    CancellationTokenSource _source = new CancellationTokenSource();
    public async Task TaskAction()
    {
        var task = Task.Run(async delegate
        {
            await TaskRun();
        }, _source.Token);

        //TaskCancel();

        try
        {
            task.Wait();
        }
        catch (Exception ex)
        {

        }
    }
    public async Task TaskRun()
    {
        if (_source.IsCancellationRequested)
        {
            _source.Token.ThrowIfCancellationRequested();
        }

        SpeechSynthesizer _speechSynthesizer = new SpeechSynthesizer();
        _speechSynthesizer.SpeakAsync("This is a test prompt");
    }
    public void TaskCancel()
    {
        _source.Cancel();
    }
}
如果调用
TaskAction()
中的
taskanccel()
,将捕获任务取消异常

如果从对象外部调用
TaskCancel()
,则不会捕获已取消的异常

以下是一些代码,用于演示未捕获已取消异常的位置:

taskObject = new TaskObject();
await taskObject.TaskAction();
taskObject.TaskCancel();

如何从对象外部调用
TaskCancel()
,以便捕获已取消的异常?

取消需要合作
Task.Run
不知道计划的委托可能有什么副作用,因此,
Task.Run
可以检查
CancellationToken
并抛出OCE(而不会使应用程序处于潜在不一致的状态)的唯一逻辑安全点在异步操作开始之前-在该点之后,由用户代码检查令牌

问题是,您的用户代码大部分时间都在等待
SpeechSynthesizer.SpeakAsync
,它没有接受
取消令牌的重载

SpeechSynthesizer
有一个
SpeakAsyncCancelAll
方法,您可以像这样插入它:

public async Task TaskRun(CancellationToken ct)
{
    ct.ThrowIfCancellationRequested();

    SpeechSynthesizer _speechSynthesizer = new SpeechSynthesizer();

    using (ct.Register(() => _speechSynthesizer.SpeakAsyncCancelAll())) {
        await _speechSynthesizer.SpeakAsync("This is a test prompt");
    }
}

我无法告诉您这是否会产生异常,表明操作已取消-您需要亲自尝试查看。

取消需要合作
Task.Run
不知道计划的委托可能有什么副作用,因此,
Task.Run
可以检查
CancellationToken
并抛出OCE(而不会使应用程序处于潜在不一致的状态)的唯一逻辑安全点在异步操作开始之前-在该点之后,由用户代码检查令牌

问题是,您的用户代码大部分时间都在等待
SpeechSynthesizer.SpeakAsync
,它没有接受
取消令牌的重载

SpeechSynthesizer
有一个
SpeakAsyncCancelAll
方法,您可以像这样插入它:

public async Task TaskRun(CancellationToken ct)
{
    ct.ThrowIfCancellationRequested();

    SpeechSynthesizer _speechSynthesizer = new SpeechSynthesizer();

    using (ct.Register(() => _speechSynthesizer.SpeakAsyncCancelAll())) {
        await _speechSynthesizer.SpeakAsync("This is a test prompt");
    }
}

我无法告诉您这是否会产生一个异常,表明该操作已被取消-您需要亲自尝试查看。

忽略SpeechSynthesizer,我说的对吗?启动Task.Run时,除非在函数开始时,否则无法检测取消请求?@user3736648,你似乎有正确的想法,但措辞需要润色(见第一段)。简单地说,
Task.Run
在线程池上执行委托之前,一开始就检查一次
CancellationToken
。一旦委托调用进行,就没有任何
任务。运行
可以完成。谢谢。除了Task.Run之外,是否有一种正确的方法来创建可以随时取消的线程?@user3736648,这在技术上是不可能的(因为这将使我们很难推断支持取消的系统的状态)。您需要的是协同取消(即支持本机取消的API,如我前面提到的
speakasyncancelall
调用)。MSDN:当然,您可以放弃异步操作(在本例中为语音播放),但这正是它听起来的样子:即使取消了
任务
,合成器仍将继续播放:忽略SpeechSynthesis,我所说的当启动Task.Run时,除非在函数开始时?@user3736648,您似乎有正确的想法,但措辞需要一些修饰(见第一段),否则无法检测取消请求。简单地说,
Task.Run
在线程池上执行委托之前,一开始就检查一次
CancellationToken
。一旦委托调用进行,就没有任何
任务。运行
可以完成。谢谢。除了Task.Run之外,是否有一种正确的方法来创建可以随时取消的线程?@user3736648,这在技术上是不可能的(因为这将使我们很难推断支持取消的系统的状态)。您需要的是协同取消(即支持本机取消的API,如我前面提到的
speakasyncancelall
调用)。MSDN:当然,您可以放弃异步操作(在本例中为语音播放),但这正是它听起来的样子:合成器将继续播放,即使
任务被取消: