情况是这样的,这是代码         port.DataReceived += comm_DataReceived;//注册接受串口数据的事件,意思是只要串口有数据来,就触发响应函数        }
        void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            MethodInvoker dataremi = new MethodInvoker(updatemainlable);//异步形式,为了能访问父进程的控件
            IAsyncResult iar=BeginInvoke(dataremi);//开始
            Thread.sleep(1000); //没这句话,UI界面停止更新。疑问之处。
            if (iar.IsCompleted)//判断串口数据接受的线程有没有执行好,好了就做下面的
            {
                outoffcontrol();//看看采集来的数值是否超标
                savedata();//将采集来的数据存入数据库
            }
        }功能实现的非常好!没有问题。但是当我想要看看整个程序的性能时。问题就来了。这程序在不断的创建新的线程,几分钟就能创建700多个线程。
经过排查,发现只要在 comm_DataReceived 函数里出现Thread.sleep(1000); ,那么就会出现不停创建新线程的情况。
但是没有Thread.sleep(1000); 这条语句的话,程序就一直循环在updatemainlable函数的开头到Application.DoEvents();这条语句。造成该线程无法进行下去,界面的数据无法更新。所以想问问大神们,这是为什么?为什么在这样的函数里面不能有Thread.sleep这句话?

解决方案 »

  1.   

    BeginInvoke本身是用线程池来实现的,如果你用sleep,那么当前的处理线程就会被阻塞,那么当下一次接收到数据时,由于线程池中的上个线程被阻塞,那么当前就没有可以使用的线程,那么线程池就会再创建新的线程,以至于几分钟就能创建700多个线程。
    “但是没有Thread.sleep(1000); 这条语句的话,程序就一直循环在updatemainlable函数的开头到Application.DoEvents();这条语句。造成该线程无法进行下去,界面的数据无法更新。”
    别用sleep这种方式,给BeginInvoke方法中传递 callBack
      

  2.   

    多谢大神们提醒!!!!!!真心醍醐灌顶啊!原来是这样!我去好好研究这个callBack!
      

  3.   

    BeginInvoke是异步的,他有个回调参数callback,传入AsyncCallback就行了,注意如果是访问UI线程要Form.Invoke()
      

  4.   

    Form.Invoke()在其他线程里直接调用就行了,具体查下MSDN吧
      

  5.   

    如果不怕麻烦,可以尝试使用一两回 backgroundworker。这个机制比较“规范”。虽然有些繁琐。你的comm_DataReceived方法中应该仅仅启动一个工作线程,而注册之后不用等线程实际开始,comm_DataReceived方法本身就应该结束了。所以这个方法执行起来瞬间就完了,然后主线程才可以去处理显示。if(iar.IsCompleted) 这类语句阻塞了主线程。你其实使用了一个异步编程的语句,却在做模拟同步程序、进行阻塞的事情。所以异步编程时,最忌讳地就是轻易写出阻塞父线程结束的语句。
      

  6.   

    最忌讳地就是轻易写出阻塞父线程结束的语句  -->  最忌讳地就是轻易写出阻塞父线程的执行方法结束的语句
    这里问题的关键不是Thread.Sleep,它只是让阻塞之后的程序变得性能更差、逻辑更糟。导火索还是if(iar.IsCompleted)这类语句的问题。
      

  7.   

    啊哦. 多线程很郁闷 我来学习下
    我有个程序用了backgroundworker 读取几M 或几百M的txt文件 就会卡死 纠结啊