Exemplo de código de comunicação de porta serial usando a API Async no .net 4.5?

Alguém pode me indicar um exemplo de trabalho que usa a API .net 4.5 Async API (assíncrona, espera, tarefa <>, ReadAsync, etc) para fazer comunicações seriais?

Tentei adaptar uma amostra serial acionada por eventos existente e estou recebendo todo tipo de comportamento horrível - erros de "porta em uso por outro aplicativo", depurador do VS2013 lançando exceções e travando - que geralmente exigem a reinicialização do PC.

editar

Eu escrevi minha própria amostra do zero. É um projeto simples do Winforms que grava na janela Saída. Três botões no formulário - Abrir porta, Fechar porta e Ler dados. O método ReadDataAsync chama SerialPort.BaseStream.ReadAsync.

A partir de agora, ele lerá dados da porta, mas estou tendo problemas para torná-los robustos.

Por exemplo, se eu desconectar o cabo serial, abrir a porta e clicar em Ler Dados duas vezes, receberei uma System.IO.IOException (que eu meio que espero), mas meu aplicativo pára de responder.

Pior ainda, quando tento interromper meu programa, o VS2013 exibe uma caixa de diálogo "Parar a depuração em andamento", que nunca é concluída, e eu não consigo nem matar o VS no Gerenciador de tarefas. Tenho que reiniciar o meu PC toda vez que isso acontece.

Não é bom.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO.Ports;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private SerialPort _serialPort;

        public Form1()
        {
            InitializeComponent();
        }

        private void openPortbutton_Click(object sender, EventArgs e)
        {
                try
                {
                    if (_serialPort == null )
                        _serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);

                    if (!_serialPort.IsOpen)
                        _serialPort.Open();

                    Console.Write("Open...");
                }
                catch(Exception ex)
                {
                    ClosePort(); 
                    MessageBox.Show(ex.ToString());
                }
        }

        private void closePortButton_Click(object sender, EventArgs e)
        {
            ClosePort();
        }

        private async void ReadDataButton_Click(object sender, EventArgs e)
        {
            try
            {
                await ReadDataAsync();
            }
            catch (Exception ex)
            {
                ClosePort();
                MessageBox.Show(ex.ToString(), "ReadDataButton_Click");
            }
        }

        private async Task ReadDataAsync()
        {
            byte[] buffer = new byte[4096];
            Task<int> readStringTask = _serialPort.BaseStream.ReadAsync(buffer, 0, 100);

            if (!readStringTask.IsCompleted)
                Console.WriteLine("Waiting...");

            int bytesRead = await readStringTask;

            string data = Encoding.ASCII.GetString(buffer, 0, bytesRead);

            Console.WriteLine(data);
        }


        private void ClosePort()
        {
            if (_serialPort == null) return;

            if (_serialPort.IsOpen)
                _serialPort.Close();

            _serialPort.Dispose();

            _serialPort = null;

            Console.WriteLine("Close");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            ClosePort();
        }

    }
}

questionAnswers(3)

yourAnswerToTheQuestion