标签: cancellationtokensource

你如何捕获CancellationToken.Register回调异常?

我正在使用异步I/O与HID设备进行通信,并且我希望在超时时抛出一个可捕获的异常.我有以下读取方法:

public async Task<int> Read( byte[] buffer, int? size=null )
{
    size = size ?? buffer.Length;

    using( var cts = new CancellationTokenSource() )
    {
        cts.CancelAfter( 1000 );
        cts.Token.Register( () => { throw new TimeoutException( "read timeout" ); }, true );
        try
        {
            var t =  stream.ReadAsync( buffer, 0, size.Value, cts.Token );
            await t;
            return t.Result;
        }
        catch( Exception ex )
        {
            Debug.WriteLine( "exception" );
            return 0;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

从Token的回调抛出的异常不会被任何try/catch块捕获,我不知道为什么.我以为它会被等待,但事实并非如此.有没有办法捕获这个异常(或让它由Read()的调用者捕获)?

编辑: 所以我重新阅读msdn上的文档,它说:"委托生成的任何异常都将从此方法调用中传播出来."

我不确定"传播出这个方法调用"是什么意思,因为即使我将.Register()调用移到try块中,异常仍然没有被捕获.

c# task-parallel-library cancellationtokensource

9
推荐指数
3
解决办法
6281
查看次数

正确使用CancellationToken

这是我的情况:

    private CancellationTokenSource cancellationTokenSource;
    private CancellationToken cancellationToken;

    public IoTHub()
    {
        cancellationTokenSource = new CancellationTokenSource();
        cancellationToken = cancellationTokenSource.Token;

        receive();
    }

    private void receive()
    {
        eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, iotHubD2cEndpoint);
        var d2cPartitions = eventHubClient.GetRuntimeInformation().PartitionIds;

        foreach (string partition in d2cPartitions)
        {
            ReceiveMessagesFromDeviceAsync(partition, cancellationToken);
        }
    }

    private async Task ReceiveMessagesFromDeviceAsync(CancellationToken ct)
    {
        var eventHubReceiver = eventHubClient.GetDefaultConsumerGroup().CreateReceiver(partition, DateTime.UtcNow);

        while (true)
        {
            if(ct.IsCancellationRequested)
            {
                break;
            }

            EventData eventData = await eventHubReceiver.ReceiveAsync();
            if (eventData == null) continue;

            string data = Encoding.UTF8.GetString(eventData.GetBytes());

            // Javascript function with Websocket
            Clients.All.setMessage(data);
        } …
Run Code Online (Sandbox Code Playgroud)

c# cancellationtokensource cancellation-token

9
推荐指数
1
解决办法
6199
查看次数

`CancellationTokenSource.TryReset` 的用例是什么?

CancellationTokenSourceTryReset()会员。该文档看起来如此严格,让我想知道它为什么存在。

  • 只有在没有人调用Cancel()它的情况下它才会起作用。
  • 仅当使用其令牌发出的任何先前异步操作已完成时才有效,这意味着(我认为)我需要挂起我的任务对象来跟踪它是否仍在运行
  • 当其他人试图取消操作时调用是不安全的,需要

那么人们为什么要费心呢TryReset?为什么不简单地为每个异步操作创建一个全新的CancellationTokenSource,然后在操作完成且不再需要取消后将其丢弃?CancellationTokenSource创建一个对象是否非常昂贵?

.net c# task-parallel-library cancellationtokensource

9
推荐指数
1
解决办法
1263
查看次数

在已取消的CancellationToken传递导致的HttpClient挂

我想用一个CancellationToken取消的呼叫HttpClient.PostAsJsonAsync.然而,以下设置调用PostAsJsonAsync无限期挂起(我离开它运行数分钟).

CancellationTokenSource source = new CancellationTokenSource();
source.Cancel();
HttpClient client = new HttpClient();

try
{
    var task = client.PostAsJsonAsync<MyObject>("http://server-address.com",
        new MyObject(), source.Token);

    task.Wait();
}
catch (Exception ex)
{
    //Never gets hit.
}
Run Code Online (Sandbox Code Playgroud)

请注意,我传递一个已经取消了CancellationTokenSource-我有同样的问题,如果我取消使用令牌Task.Delay有短暂的延迟.

我知道我可以简单地检查是否该令牌之前已经电话取消,但即便如此,我也有同样的问题,如果令牌被短暂延迟后取消,也就是说,它不是在方法调用之前取消,但因此后不久变得它.

所以我的问题是,是什么原因造成这一点,我可以做些什么来解决什么/解决这个问题?

编辑

对于那些寻找一个变通方法,通过@Darrel米勒的回答启发,我想出了下面的扩展方法:

public static async Task<HttpResponseMessage> PostAsJsonAsync2<T>(this HttpClient client, string requestUri, T value, CancellationToken token)
{
    var content = new ObjectContent(typeof(T), value, new JsonMediaTypeFormatter());
    await content.LoadIntoBufferAsync();

    return await client.PostAsync(requestUri, content, token);
}
Run Code Online (Sandbox Code Playgroud)

c# task-parallel-library cancellationtokensource dotnet-httpclient

8
推荐指数
2
解决办法
3223
查看次数

Task.Delay没有被取消?

我正在尝试为游戏构建界面.游戏运行1分钟.该GetStop方法后60秒游戏停止.该游戏方法在游戏开始时和退出方法退出游戏.理想情况下,我想要的是当我在30秒后退出游戏时,计时器应该重置,点击"播放"按钮,计时器应该再次运行1分钟.这样下一场比赛就可以运行1分钟.如果我再次按退出按钮,则应重置计时器以进行下一场比赛.

但是,我的代码中似乎存在某个问题.每当我执行quit方法时,计时器似乎都保存在该状态.所以,如果我在30秒内退出比赛,那么下一场比赛将持续30秒.如果我在50秒内退出比赛,下一场比赛将只持续10秒.理想情况下,计时器应该重置但不会重置.

我在这里没有想法.任何人都可以提供一些建议?

private async Task GetStop(CancellationToken token)
{ 
    await Task.Run(async () =>
    {
        token.ThrowIfCancellationRequested();
        await Task.Delay(TimeSpan.FromSeconds(60), token);

        token.ThrowIfCancellationRequested();
        if (!token.IsCancellationRequested)
        {
            sendMessage((byte)ACMessage.AC_ESCAPE); 
        }
    }, token);
}

public async void Play()
{         
        sendMessage((byte)ACMessage.AC_START_RACE); 
        _cts.Cancel();

        if (_cts != null)
        {
            _cts.Dispose();
            _cts = null;
        }
        _cts = new CancellationTokenSource(); 
        await GetStop(_cts.Token);
   }

public void Quit()
{
        _cts.Cancel();
        if (_cts != null)
        {
            _cts.Dispose();
            _cts = null;
        }
    //
}
Run Code Online (Sandbox Code Playgroud)

c# task-parallel-library cancellation cancellationtokensource

8
推荐指数
1
解决办法
285
查看次数

使用TPL Dataflow,我可以取消所有帖子然后添加一个吗?

使用TPL Dataflow库,我想做这样的事情:

myActionBlock.Post(newValue, cancelAllPreviousPosts: true);
Run Code Online (Sandbox Code Playgroud)

似乎ActionBlock上的取消令牌取消了整个事情; 如果我设置了那个,我必须创建一个新的ActionBlock.是否可以使用ActionBlock进行部分取消?

尚未尝试尚未处理的帖子.如果有一些取消令牌可用于检查当前正在执行的帖子,那将是很好的.

c# task-parallel-library cancellationtokensource tpl-dataflow

7
推荐指数
1
解决办法
1101
查看次数

当CancellationToken请求取消时,NamedPipeServerStream.ReadAsync()不会退出

当NamedPipeServer流从管道读取任何数据时,它不响应 CancellationTokenSource.Cancel()

这是为什么?

如何限制我在服务器中等待来自客户端的数据的时间?

代码重现:

static void Main(string[] args)
{
    Server();
    Clinet();
    Console.WriteLine("press [enter] to exit");
    Console.ReadLine();
}

private static async Task Server()
{
    using (var cancellationTokenSource = new CancellationTokenSource(1000))
    using (var server = new NamedPipeServerStream("test",
        PipeDirection.InOut,
        1,
        PipeTransmissionMode.Byte,
        PipeOptions.Asynchronous))
    {
        var cancellationToken = cancellationTokenSource.Token;
        await server.WaitForConnectionAsync(cancellationToken);
        await server.WriteAsync(new byte[]{1,2,3,4}, 0, 4, cancellationToken);
        var buffer = new byte[4];
        await server.ReadAsync(buffer, 0, 4, cancellationToken);
        Console.WriteLine("exit server");
    }
}

private static async Task Clinet()
{
    using (var client = new NamedPipeClientStream(".", "test", …
Run Code Online (Sandbox Code Playgroud)

c# named-pipes async-await cancellationtokensource

7
推荐指数
2
解决办法
651
查看次数

f#async何时检查其CancellationToken?

我正在阅读F#的乐趣和利润 - 异步编程.在取消工作流程下,他们有以下示例:

let testLoop = async {
    for i in [1..100] do
    // do something
    printf "%i before.." i

    // sleep a bit 
    do! Async.Sleep 10  
    printfn "..after"
    }

open System
open System.Threading

// create a cancellation source
let cancellationSource = new CancellationTokenSource()

// start the task, but this time pass in a cancellation token
Async.Start (testLoop,cancellationSource.Token)

// wait a bit
Thread.Sleep(200)  

// cancel after 200ms
cancellationSource.Cancel()
Run Code Online (Sandbox Code Playgroud)

他们说:

在F#中,任何嵌套的异步调用都会自动检查取消令牌!

在这种情况下,它是线:

do! Async.Sleep(10) 
Run Code Online (Sandbox Code Playgroud)

从输出中可以看出,此行是取消发生的位置.

但是,对我来说(VS2010,F#2.0,F#Interactive)我得到以下输出.请注意..after …

f# asynchronous cancellationtokensource cancellation-token

6
推荐指数
1
解决办法
1166
查看次数

如何使用CancellationToken取消任务?

所以我有这个代码:

//CancelationToken
CancellationTokenSource src = new CancellationTokenSource();
CancellationToken ct = src.Token;
ct.Register(() => Console.WriteLine("Abbruch des Tasks"));
//Task
Task t = new Task(() =>
{
    System.Threading.Thread.Sleep(1000);
    if (ct.IsCancellationRequested)
    {
        try
        {
            //Throw
            ct.ThrowIfCancellationRequested();                        
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine(
                "ThrowIfCancellationRequested() liefert eben eine Exception");
        }
    }             

}, ct);
//Run Task and Cancel
t.Start();
src.CancelAfter(350);
t.Wait();

// Get Information
Console.WriteLine("Canceled: {0} . Finished: {1} . Error: {2}",
                    t.IsCanceled, t.IsCompleted, t.IsFaulted);
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下我取消了我的任务,但我的输出最后是:"取消:假.完成:真.错误:错误"

在我看来,它应该是"取消:真实.完成:假".为什么我得到这个结果?因为我试图抓住异常?

我试过没有try-catch块,但是由于OperationCanceledException,我的程序停止了.有人能帮助我吗?

c# task task-parallel-library cancellationtokensource

6
推荐指数
1
解决办法
3314
查看次数

HttpClient取消不会杀死底层TCP调用

我正在尝试将HttpClient调用的默认超时设置为5秒.

我通过这样做了CancellationTokenSource.

这是相关的代码:

var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(TimeSpan.FromSeconds(5));
var result = _httpClient.SendAsync(request, cancellationToken.Token);
Run Code Online (Sandbox Code Playgroud)

按照调用代码获取"任务被取消"错误(我在.NET 4.7控制台应用程序中测试)的预期工作,但我注意到在Fiddler中请求仍然运行1分钟,直到它最终放弃:

在此输入图像描述

有人可以解释这种行为吗?

我希望在触发取消时基础请求也会被取消.

_httpClient 实例化如下: new HttpClient { BaseAddress = baseAddress }

我知道有Timeout设置,但不确定我是否应该使用它或取消令牌?我的猜测是Timeout针对非异步/等待的情况?

c# cancellationtokensource dotnet-httpclient cancellation-token

6
推荐指数
1
解决办法
932
查看次数