具有CancellationToken和ReadTimeout的异步串行端口

时间:2017-12-08 21:24:50

标签: c# asynchronous serial-port task cancellation

我正在尝试将SerialPort的read方法包装在一个可以等待的任务中,这样我就能从使用CancellationToken和SerialPort对象的超时中获益。我的问题是我似乎无法让Task抛出CancellationException。这是我的代码......

    static CancellationTokenSource Source = new CancellationTokenSource();

    static void Main(string[] args)
    {
        TestAsyncWrapperToken();
        Console.WriteLine("Press any key to cancel");
        Console.ReadKey(true);
        Source.Cancel();
        Console.WriteLine("Source.Cancel called");
        Console.ReadLine();
    }

    static async void TestAsyncWrapperToken()
    {
        try
        {
            using (var Port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One))
            {
                Port.Open();
                var Buffer = new byte[1];
                await Task.Factory.StartNew(() =>
                {
                    Console.WriteLine("Starting Read");
                    Port.ReadTimeout = 5000;
                    Port.Read(Buffer, 0, Buffer.Length);                        
                }, Source.Token);
            }
        }
        catch (TaskCanceledException)
        {
            Console.WriteLine("Task Cancelled");
        }
        catch (TimeoutException)
        {
            Console.WriteLine("Timeout on Port");
        }
        catch (Exception Exc)
        {
            Console.WriteLine("Exception encountered {0}", Exc);
        }
    }

是因为Port.Read方法是阻塞调用吗?有什么建议?

1 个答案:

答案 0 :(得分:0)

可以想到两种方法。

  1. 使用ReadAsync
    它是从SreiaPort对象的BaseStream property获取Stream对象并使用Stream.ReadAsync Method (Byte[], Int32, Int32, CancellationToken)

    虽然内容不完全匹配,但请参阅此内容 How to cancel Stream.ReadAsync?
    NetworkStream.ReadAsync with a cancellation token never cancels

  2. 使用DataReceivedEventSerialDataReceivedEventHandler
    更改以便将DataReceivedEvent用作触发器 请参阅本文的答案 Sample serial port comms code using Async API in .net 4.5?

  3. P.S。
    如果您想使用.NET 4.0或更低版本,以下文章将会有所帮助 它也将与上述有关的知识 If you must use .NET System.IO.Ports.SerialPort
    Reading line-by-line from a serial port (or other byte-oriented stream)