标签: cancellation-token

停止线程、ManualResetEvent、易失性布尔值或取消令牌

我在 Windows 服务中有一个线程 (STAThread),它执行大量工作。当 Windows 服务重新启动时,我想优雅地停止这个线程。

我知道几种方法

  • 一个不稳定的布尔值
  • 手动重置事件
  • 取消令牌

据我发现 Thread.Abort 是不行的......

最佳做法是什么?这项工作是在另一个类中执行的,而不是线程启动的类,因此有必要在构造函数中引入一个 cancelToken 参数,或者例如有一个 volatile 变量。但我就是不知道什么是最聪明的。

更新
只是为了澄清一点,我已经总结了我正在谈论的一个非常简单的例子。如前所述,这是在 Windows 服务中完成的。现在我正在考虑一个在循环中检查的可变布尔值或一个取消令牌......我不能等待循环完成,如下所述,它可能需要几分钟,使服务器的系统管理员相信当他们需要重新启动服务时,服务出了点问题......我可以毫无问题地将循环中的所有工作都毫无问题地删除,但是我不能用 Thread.Abort 来做到这一点,它是“邪恶的”,而且是一个 COM接口被调用,所以需要一个小的清理。

Class Scheduler{
  private Thread apartmentThread;
  private Worker worker;

  void Scheduling(){
    worker = new Worker();
    apartmentThread = new Thread(Run);
    apartmentThread.SetApartmentState(ApartmentState.STA);
    apartmentThread.Start();    
  }

  private void Run() {
    while (!token.IsCancellationRequested) {
      Thread.Sleep(pollInterval * MillisecondsToSeconds);
      if (!token.IsCancellationRequested) {
        worker.DoWork();
      }
    }
  }
}

Class Worker{
  //This will take several minutes....
  public void DoWork(){
    for(int i = 0; i < …
Run Code Online (Sandbox Code Playgroud)

c# multithreading cancellation cancellation-token

5
推荐指数
2
解决办法
9292
查看次数

等待方法中的取消令牌

将令牌放在任务的构造函数中的原因很多,如下所述: 任务构造器中的取消令牌:为什么?

通过使用关键字async / await,它如何工作?例如下面的代码:

public async Task MethodAsync(CancellationToken token)
{
  await Method01Async();
  await Method02Async();
}
Run Code Online (Sandbox Code Playgroud)

虽然这是一个异步过程。我很快就使用了“ Task.StartNext”或“ Task.Run”或“新任务”。为了能够指定我的取消令牌,该怎么办?

c# async-await async-ctp cancellation-token

5
推荐指数
1
解决办法
6593
查看次数

如何使用取消令牌取消 C# 中的阻塞任务?

我有一个总是被阻止的任务,我有一个 CancellationToken 传递给它,用于取消任务。然而,设置为在任务取消时执行的继续任务永远不会执行。代码是:

    _tokenSrc = new CancellationTokenSource();
    var cnlToken = _tokenSrc.Token;

    Task.Run(() => 
          // _stream.StartStream() blocks forever  
          _stream.StartStream(), cnlToken)
        .ContinueWith(ant =>
        {
            _logger.Warn("Stream task cancellation requested, stopping the stream");
            _stream.StopStream();
            _stream = null;
            _logger.Warn("Stream stopped and task cancelled");
        }, TaskContinuationOptions.OnlyOnCanceled);
Run Code Online (Sandbox Code Playgroud)

稍后在代码中的其他地方......

_tokenSrc.Cancel();
Run Code Online (Sandbox Code Playgroud)

我不得不为 _stream.StartStream() 使用 Task 的原因是这个调用永远阻塞(一个我无法控制的 api,请注意 _stream 指的是一个第三方 Api,它从 web 服务流数据)所以我不得不调用它在另一个线程上。

取消任务的最佳方法是什么?

c# task-parallel-library cancellation-token

5
推荐指数
1
解决办法
3132
查看次数

CancellationTokenSource的行为不符合预期

在这种情况下预期的是,如果用户通过按Enter键取消任务,则挂起的另一个任务ContinueWith将运行,但事实并非如此,AggregateException尽管显式处理ContinueWith显然没有被执行,但仍保持抛出.
请问下面的任何澄清?

class Program
{
    static void Main(string[] args)
    {
        CancellationTokenSource tokensource = new CancellationTokenSource();
        CancellationToken token = tokensource.Token;

        Task task = Task.Run(() =>
        {
            while (!token.IsCancellationRequested)
            {
                Console.Write("*");
                Thread.Sleep(1000);
            }
        }, token).ContinueWith((t) =>
        {
            t.Exception.Handle((e) => true);
            Console.WriteLine("You have canceled the task");
        }, TaskContinuationOptions.OnlyOnCanceled);

        Console.WriteLine("Press any key to cancel");
        Console.ReadLine();
        tokensource.Cancel();
        task.Wait();
    }
}
Run Code Online (Sandbox Code Playgroud)

.net c# multithreading task-parallel-library cancellation-token

5
推荐指数
1
解决办法
723
查看次数

取消所有异步任务

是否可以在不知道当前正在运行的情况下取消所有异步方法?

例如,我有几个可能运行异步任务的类:

class Class1
{
    public async void SomeTask()
    {
        for (int i = 0; i < 5; i++)
        {
            // Doing some job
            await Task.Delay(2000);
        }
    }
}

class Class2
{
    public async void ContinuouslyTask()
    {
        for (;;)
        {
            // Doing some job on background
            await Task.Delay(1000);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想在注销之前关闭每个异步任务:

class Program
{
    static void Main(string[] args)
    {
        var p = new Program();
        var c1 = new Class1();
        var c2 = new Class2();

        c1.SomeTask();
        c2.ContinuouslyTask(); 

        while (Console.ReadKey().Key != …
Run Code Online (Sandbox Code Playgroud)

c# asynchronous async-await cancellation-token

5
推荐指数
1
解决办法
4446
查看次数

CancellationToken 如何在 Web 请求上传输

我正在研究通过 WebAPI 取消异步请求,

最近我发现最新版本的 WebApi(不是 .NET-Core 的)支持取消令牌。作为测试,我编写了这段代码。

[HttpGet]
[Route("LongRequest")]
public async Task<string> VeryLongRequest(string Key, CancellationToken token)
{
    for (int i = 0; i < 5; ++i)
    {
        if (false == token.IsCancellationRequested)
        {
            Thread.Sleep(5000);
        }
        else
        {
            Trace.WriteLine("Cancelled");
        }
    }

    return "Complete";
}
Run Code Online (Sandbox Code Playgroud)

当用户关闭窗口/刷新/或导航到新页面(不在 SPA 上)时,此代码有效,并且取消令牌会更新。

由于 HTTP 请求假设是无状态的,取消映射如何映射回请求?

以及如何从我的客户手动调用取消?

c# asynchronous stateless asp.net-web-api cancellation-token

5
推荐指数
0
解决办法
567
查看次数

如何使用作为参数传递的 CancellationToken 来模拟方法?

我最近正在学习和使用 Polly 来为我的代码添加弹性,特别是对于超时和重试策略。但是,我不知道如何使用 polly 对代码进行单元测试。更具体地说,我不知道如何模拟以 Cancellation Token 作为参数的方法。下面是我的代码结构

public class Caller
{
     private IHttpManager httpManager;
     private IAsyncPolicy<HttpResponseMessage> policyWrap;

     public Caller(IHttpManager httpManager, IAsyncPolicy<HttpResponseMessage> policyWrap)
     {
        this.httpManager= httpManager;
        this.policyWrap = policyWrap;
     }


     public async Task CallThirdParty()
     {      

        HttpResponseMessage httpResponse = await policyWrap.ExecuteAsync(async ct => await httpManager.TryCallThirdParty(ct), CancellationToken.None);

     }

}

public interface IHttpManager
{
    Task<HttpResponseMessage> TryCallThirdParty(CancellationToken cancellationToken);
}
Run Code Online (Sandbox Code Playgroud)

下面是我打算运行但不知道如何运行的单元测试。

[Test]
public void TestBehaviourUnderTimeoutPolicy()
{
     // Set up the timeout policy such that the governed delegate will terminate after 1 sec if no response …
Run Code Online (Sandbox Code Playgroud)

c# moq cancellation-token polly

5
推荐指数
2
解决办法
6378
查看次数

CancellationToken 在 asp.net 核心中不起作用

我正在使用 Asp.net Core API 并设置如下服务:

services
    .Configure<AppOptions>(_configuration.GetSection("app"))
    .AddMvcCore(options =>
        {
            options.RespectBrowserAcceptHeader = true;
            options.OutputFormatters.Add(new XmlSerializerOutputFormatter());
            options.InputFormatters.Add(new XmlSerializerInputFormatter(options));
        })
    .AddFormatterMappings()
    .AddJsonFormatters()
    .AddXmlSerializerFormatters()
    .AddCors();
Run Code Online (Sandbox Code Playgroud)

之后,我创建了一个带有 CancellationToken 参数的 API,如下所示:

[HttpGet("list")]
public async Task<ActionResult<IEnumerable<string>>> Get(CancellationToken cancellationToken)
{
    var result = await _orderBusinessService.GetList(cancellationToken);

    return Ok(result);
}
Run Code Online (Sandbox Code Playgroud)

当我从 Postman 或浏览器调用此 API 时,我得到以下响应:

415 不支持的媒体类型

当我添加[FromQuery]到cancellationToken时,就可以了。

实际上,这似乎CancellationTokenModelBinder行不通。

我不知道为什么?有人有任何想法吗?

c# cancellation-token asp.net-core asp.net-core-webapi

5
推荐指数
1
解决办法
1463
查看次数

如何获得 Task.WhenAny 对 Task 和 CancellationToken 的影响?

我有交互式任务,在“最坏”场景中根本不执行,因此它由TaskCompletionSource.

我想等待此任务完成,或者我收到的令牌被取消——以先发生者为准。这种工作的完美工具将是Task.WhenAny,唯一的问题是它只需要任务,而我有一个Task和一个CancellationToken

如何等待(异步地,像Task.WhenAny)触发的第一个事件——完成的任务或取消的令牌?

async Task MyCodeAsync(CancellationToken token)
{
  var tcs = new TaskCompletionSource<UserData>(); // represents interactive part

  await Task.WhenAny(tcs.Task, token); // imaginary call

  UserData data = tcs.Task.Result; // user interacted, let's continue
  ...
}
Run Code Online (Sandbox Code Playgroud)

我不创建/管理令牌,所以我无法更改它。我必须处理它。

更新:对于这种特殊情况,可以使用Register令牌上的方法取消TaskCompletionSource. 有关更通用的方法,请参阅 Matthew Watson 的回答。

c# asynchronous task async-await cancellation-token

5
推荐指数
3
解决办法
1342
查看次数

将 OperationCanceledException 关联到 CancellationToken 的正确方法

我正在使用一个支持取消的异步 api,我正在向该 api 传递一个CancellationToken实例。像往常一样,如果在传递的令牌上请求取消,我正在调用的 api 将抛出一个OperationCanceledException(这是 .NET 框架的标准合作取消模式)。

我希望能够捕获OperationCanceledException 当且仅当它是由于取消提供的取消令牌而引发的异常时。

以下代码说明了我要实现的目标:

try 
{
    await _service.DoSomethingAsync(cancellationToken: token);
}
catch (OperationCanceledException ex) when ( /* here I want a condition signifying that the OperationCanceledException is caused by the cancellation of the token object */)
{
    // avoid logging the exception: this is raised by design (cooperative cancellation)
    throw;
}
catch (Exception ex) 
{
    _logger.LogError(ex, "An error occurred: {0}", ex.Message);
    throw;
}
Run Code Online (Sandbox Code Playgroud)

对于上面代码的异常过滤器,我基本上有两个想法:

  • 检查对象的IsCancellationRequested属性token …

c# cancellation async-await cancellation-token .net-core

5
推荐指数
1
解决办法
71
查看次数