我写了一个小程序用于监听串口的数据,第一次点监听,然后暂停,都还正常,但是再点监听的时候就会造成蓝屏死机.我是在虚拟机里面用SerialNull 模拟的串口通信,用别的测试软件通信正常.串口消息是用测试软件发的,监听正常,但是就是在暂停和监听切换的时候会造成蓝屏死机。请大家帮帮忙看看问题在哪里。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace PortTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }        private SerialPort Sp = new SerialPort();
        public delegate void SetTextCallback(string text);
        private Thread newThread = null;
        string readstr = null;
        
        private void SetText(string text)
        {
            if (this.textBox_data.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox_data.Text = text;
            }         }
        private void ThreadProcSafe()
        {
            this.SetText(readstr);
        }
        public void Sp_DataReceived(object sender,System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            byte[]  readBuffer = new byte[Sp.ReadBufferSize];
            Sp.Read(readBuffer, 0, readBuffer.Length);
            readstr =Encoding.UTF8.GetString(readBuffer);            
            this.newThread = new Thread(new ThreadStart(this.ThreadProcSafe));
            this.newThread.Start();
        }        private void button1_Click(object sender, EventArgs e)
        {
            Sp.PortName = "COM4";
            Sp.BaudRate = 9600;
            Sp.Parity = Parity.None;
            Sp.StopBits = StopBits.One;
            
            Sp.DataReceived += new SerialDataReceivedEventHandler(Sp_DataReceived);
            Sp.ReceivedBytesThreshold = 1;
            try
            {
                Sp.Open();
                button_pause.Enabled = true;
                button_listen.Enabled = false;
            }
            catch
            {
                MessageBox.Show("端口COM4打开失败!");
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            newThread.Abort();
            Sp.Close();
            button_listen.Enabled = true;
            button_pause.Enabled = false;
        }       
    }
}

解决方案 »

  1.   

    1.这样的线程操作不安全,把button1_Click中的方法单独提到一个线程中去操作,尽量不要使用newThread.Abort();来停止线程,建立线程的标示符,bool flag,使用标示符去通知线程方法去return结束掉,否则线程很可能会出错.
    2.Sp在每次open之前,必须进行IsOpen检测,以判断是否已经打开,你的蓝屏错误很有可能是这个原因造成,因为Sp.close()是需要一定时间的,如果在未结束close的时候又再进行打开,很可能会崩溃
      

  2.   


    this.BeginInvoke(d, new object[] { text });
    改为异步调用.Sp_DataReceived本身就是在一个新的线程当中在执行,里面就不需要再new一个线程了. 暂停就直接这样了
     Sp.DataReceived -= Sp_DataReceived;
    Sp.Close();
      

  3.   

    问题没有解决,我把
    this.newThread = new Thread(new ThreadStart(this.ThreadProcSafe));
    this.newThread.Start();
    这2句给屏蔽了,依然蓝屏。
    不接收数据肯定没有问题,我是虚拟了com3和com4,com3发送信号,一旦有信号过来,就蓝屏。
    Sp.DataReceived += new SerialDataReceivedEventHandler(Sp_DataReceived);
    Sp.ReceivedBytesThreshold = 1;
      

  4.   

    我发现问题应该出自
    Sp.Read(readBuffer, 0, readBuffer.Length);
    这一句,如果每次到这里中断,就没问题,把这个中断点去掉,然后点继续,马上就蓝屏。
      

  5.   


    byte[] readBuffer = new byte[Sp.BytesToRead];
    Sp.Read(readBuffer, 0, readBuffer.Length);数组的长度设为需要的数量。
    ReadBufferSize是接收缓冲区的容量,它可能大于实际接收到的大小
      

  6.   

    实际接收的大小是小于sp.BytesToRead.
      

  7.   

    2楼的异步方法是指写textbox的时候用的吧。那个地方我屏蔽了依然死机。
      

  8.   


    如果有这个情况.加
            System.Threading.Thread.Sleep(1000);试一下.
      

  9.   

    按我之前说的改了后,你直接在电脑的串口上测试,确认没有问题在到虚拟机里面用SerialNull 模拟的串口通信。这个可能是SerialNull 模拟的串口出现问题了
      

  10.   

    SerialNull 没有问题,我用别人做的串口测试软件试验的时候,开关串口都很正常,我自己做了个定时发送的程序,每次发送随机数,用别人的串口测试软件接收也正常。问题肯定是我做的这个数据接收程序的问题。
    Sp.BytesToRead =4096,我发送的数据就2字节都出问题。
      

  11.   

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.IO.Ports;
    using System.Threading;
    namespace PortTest
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }        private SerialPort Sp = new SerialPort();
            public delegate void SetTextCallback(string text);
            //private Thread newThread = null;
            string readstr = null;        private void SetText(string text)
            {
                if (this.textBox_data.InvokeRequired)
                {
                    SetTextCallback d = new SetTextCallback(SetText);
                    this.BeginInvoke(d, new object[] { text });
                }
                else
                {
                    this.textBox_data.Text = text;
                }        }        public void Sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                try
                {
                    if (Sp.IsOpen == true)
                    {
                        byte[] readBuffer = new byte[Sp.ReadBufferSize];
                        Sp.Read(readBuffer, 0, readBuffer.Length);
                        readstr = Encoding.UTF8.GetString(readBuffer);                    SetText(readstr);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }        }        private void button1_Click(object sender, EventArgs e)
            {
                Sp.PortName = "COM4";
                Sp.BaudRate = 9600;
                Sp.Parity = Parity.None;
                Sp.StopBits = StopBits.One;            Sp.DataReceived += new SerialDataReceivedEventHandler(Sp_DataReceived);
                Sp.ReceivedBytesThreshold = 1;
                try
                {
                    Sp.Open();
                    button_pause.Enabled = true;
                    button_listen.Enabled = false;
                }
                catch
                {
                    MessageBox.Show("端口COM4打开失败!");
                }
            }
            private void button2_Click(object sender, EventArgs e)
            {
                Sp.DataReceived -= Sp_DataReceived;
                Sp.Close();
                button_listen.Enabled = true;
                button_pause.Enabled = false;
            }
        }
    }
    简单的修改了,试试
      

  12.   

    感谢xingyuebuyu,这下子不死了。是不是问题的根源在于要在 
    public void Sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                try
                {
                    if (Sp.IsOpen == true)   //判断串口是否处于打开状态
                    {
                        byte[] readBuffer = new byte[Sp.ReadBufferSize];
                        Sp.Read(readBuffer, 0, readBuffer.Length);
                        readstr = Encoding.UTF8.GetString(readBuffer);                    SetText(readstr);
                    }
                }
    判断串口是否处于打开状态
      

  13.   

    还有 Sp.DataReceived -= Sp_DataReceived;
    这样暂停是有什么好处?不是太明白,请xingyuebuyu再给我详细解释下
      

  14.   

    判断串口是否处于打开状态,这个是进行安全性检查,防止你的程序在触发DataReceived 事件后,准备接收时,程序的其它地方有突然将串口关闭,这时你去read就会出现异常。Sp.DataReceived += new SerialDataReceivedEventHandler(Sp_DataReceived);
    进行事件绑定
    Sp.DataReceived -= Sp_DataReceived;
    就是移除事件绑定两者本来就是搭配使用的
      

  15.   

    感谢各位的帮忙。
    结贴了。
    liuh6的sleep方法可以解决一点问题,但是会带来新问题。给了一点分。
    xingyuebuyu 的代码问题都解决了。特别感谢。
     
      

  16.   

    这里可以解决你们的问题
    http://blog.csdn.net/Tylerco/archive/2010/08/06/5794275.aspx