尝试在串行端口的DataReceived事件处理程序中读取数据时显示文本时出现死锁

时间:2016-06-02 20:20:08

标签: c# multithreading events serial-port

  • 我正在PC和嵌入式设备之间实现串行协议​​。
  • 我正在从PC中以块的形式向设备发送文件内容。
  • 在我开始发送文件之前,我正在发送它的名称和大小,然后等待来自设备的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();
                }
        }
  }

1 个答案:

答案 0 :(得分:1)

这是因为Debug/gnu Hello! This program will find the area of selected figures! What is your shape? The only shapes that work are Triangles,Rectangles, and Circles circle What is the radius? 5 The area is 49.348022 What is your shape? The only shapes that work are Triangles,Rectangles, and Circles cube That is an invalid input the only shapes that work are Triangles, Rectangles, and Circles What is your shape? The only shapes that work are Triangles,Rectangles, and Circles rectangle What is the length? 2 What is the height? 4 The area is 8.000000 What is your shape? The only shapes that work are Triangles,Rectangles, and Circles 会将您传递给它的任何内容发送到UI(主)线程(您可能已经知道),但是您的UI线程已经很忙,它在Invoke中被阻止:< / p>

buttonSendFile_Click

或在这里

waitHandle_1.WaitOne();

waitHandle_2.WaitOne(); 也阻止调用 - 在调度完成之前它不会返回 - 所以你有经典的死锁。

一般来说,阻止UI线程是很糟糕的,特别是等待等待句柄。要解决您的问题 - 使用后台线程执行您现在在Invoke处理程序中执行的操作。