【问题标题】:Deadlock when trying to display text while data read in DataReceived event handler of serialport在串行端口的 DataReceived 事件处理程序中读取数据时尝试显示文本时出现死锁
【发布时间】:2016-06-02 20:20:08
【问题描述】:
  • 我正在实现 PC 和嵌入式设备之间的串行协议。
  • 我正在将文件内容从 PC 分块发送到设备。
  • 在我开始发送文件之前,我发送它的名称和大小,然后等待来自设备的 ACK,然后开始循环发送块并等待每个块的 ack。
  • 我正在使用事件将 DataReceived 线程中收到的 ACK 与发送数据块的主线程同步。

问题: 在我添加这一行之前,所有上述工作都很好:

textBoxLog.Invoke((MethodInvoker)(() => textBoxLog.AppendText(str)));

所以我可以向用户更新发送进度,当此行在代码中时,主线程中未收到事件并且程序处于死锁状态。

知道为什么吗?

这是对代码的简短总结:

    public partial class MainForm : Form
    {
        AutoResetEvent waitHandle_1 = new AutoResetEvent(false);
        AutoResetEvent waitHandle_2 = new AutoResetEvent(false);

        public MainForm()
        {
            InitializeComponent();

            try
            {
                myPort = new System.IO.Ports.SerialPort("COM37");
                myPort.BaudRate = 460800;
                myPort.Parity = System.IO.Ports.Parity.None;
                myPort.DataBits = 8;
                myPort.StopBits = System.IO.Ports.StopBits.One;
                myPort.Handshake = System.IO.Ports.Handshake.None;
                myPort.ReadTimeout = 5000;
                myPort.DataReceived += new SerialDataReceivedEventHandler(SerialPortDataReceived);

                if (myPort.IsOpen == false) //if not open, open the port
                    myPort.Open();
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
        }

        // Serial port received event handler
        private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            while (myPort.BytesToRead > 0)
            {
                var count = myPort.BytesToRead;
                var bytes = new byte[count];
                myPort.Read(bytes, 0, count);
                AddResponseBytes(bytes);
            }
        }

        List<byte> Data = new List<byte>();
        private void AddResponseBytes(byte[] bytes)
        {
            // Analyzing message byte, wait for full message
            ProcessResponse(responseData, msgType);
        }

        private void ProcessResponse(List<byte> bytes, mixCommandType responseType)
        {
            String str;

            switch (responseType)
            {
                case CommandType.PC_TO_DEVICE_RESPONSE:
                    str = "Test text";
                    waitHandle_1.Set();
                    textBoxLog.Invoke((MethodInvoker)(() => textBoxLog.AppendText(str)));
                    break;
                case CommandType.CHUNK_ACK:
                    waitHandle_2.Set();
                    break;
            }
        }

        private void buttonSendFile_Click(object sender, EventArgs e)
        {
            // Open file and send message to device with file size and wait for ACK

            waitHandle_1.WaitOne();

            Console.WriteLine("Got response - Continue to send");

            uint i = 0;
            while (i < bytes.Length)
                {
                    //Send chunk of the file to the device and whait for chunk ack
                    waitHandle_2.WaitOne();
                }
        }
  }

【问题讨论】:

    标签: c# multithreading events serial-port


    【解决方案1】:

    那是因为Invoke 将您传递给 UI(主)线程(您可能已经知道)的任何内容分派,但您的 UI 线程已经很忙,它在 buttonSendFile_Click 中被阻塞:

    waitHandle_1.WaitOne();
    

    或这里

    waitHandle_2.WaitOne();
    

    Invoke 也在阻塞调用 - 在调度完成之前它不会返回 - 所以你有典型的死锁。

    一般来说,阻塞 UI 线程是不好的,尤其是等待等待句柄。要解决您的问题 - 使用后台线程执行您现在在 buttonSendFile_Click 处理程序中执行的操作。

    【讨论】:

    • 您也可以将async 添加到事件处理程序中并一直执行异步操作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 2013-09-20
    • 2017-02-07
    相关资源
    最近更新 更多