最近遇到一个项目,需要开发一个winfrom程序,此程序的主要功能是读取USB设备中的数据,并在winfrom中绘制响应曲线.USB设备采集数据的时间可设置,如从10ms---到1s.我遇到的问题如下:当USB采集数据的时间设置为1s时,界面中的按钮控件等响应速度就变慢了.采集USB数据的功能新开了一个线程来接收.按道理讲不会出现影响主界面的情况,但是实际测试时发现USB设备数据采集时间变长时,winform界面响应受到影响,感觉是UI线程在接收数据!请大大们给点指教啊.我这样建立线程的方式是否正确,这样到底算不算开启了一个辅助线程???下面是部分代码,均在Form1.cs文件中:
        private bool bool_Isrefreshstop = false;
        private delegate void mydelegate();
        private mydelegate myfresh;
        private delegate void beginInvokeDelegate();
        private ThreadStart mystart; 
        private  Thread mythread; 
        OmniDriver.CCoWrapperClass wrapper=newOmniDriver.CCoWrapperClass();
        public  double[] spectrumArray, wavelengthArray;
 public Form1()
        {
            InitializeComponent();
            sd[0] = new PointPairList();
            list_dynamicScan[m_PairListCount] = new PointPairList();
            curves[m_PairListCount] = zedGraphControl1.GraphPane.AddCurve("AA", list_dynamicScan[m_PairListCount], Color.Red, SymbolType.None);//在绘图表面上加一条曲线,
            WrapperInit();//初始化USB设备
            Splasher.Close();
            ThreadStart mystart = new ThreadStart(refreshgraph);
            mythread = new Thread(mystart);
            mythread.IsBackground = true;

        }   private void beginInvokeMethod()
        {
            zedGraphControl1.Invalidate();
        }
        private void refreshgraph()
        {
            beginInvokeDelegate hh = new beginInvokeDelegate(beginInvokeMethod);
            while (true)
            {
                if (bool_Isrefreshstop == false)
                {
                    double xCoord = 0, yCoord = 0;
                    int i;
                    list_dynamicScan[m_PairListCount].Clear();
                    sd[0].Clear();
                    spectrumArray = ((double[])wrapper.getSpectrum(0));// 此处就是读取USB设备数据.
                    wavelengthArray = ((double[])wrapper.getWavelengths(0));
                    if (b_Filter == false)
                    {
                        for (i = 0; i < spectrumArray.Length; i++)
                        {
                            xCoord = Math.Round(((double)wavelengthArray[i]), 2);
                            yCoord = Math.Round(((double)spectrumArray[i] - (double)spectrumArrayTmp[i]) * 100f / 65535f, 2);// *6000 / ((double)((Int32)wrapper.getMaximumIntensity(0)));
                            list_dynamicScan[m_PairListCount].Add(xCoord++, yCoord++);
                        }
                    }
                    else
                    {
                        for (i = 0; i < spectrumArray.Length; i++)
                        {
                            int count = 0;
                            for (count = 0; count < 15; count++)
                            {
                                xCoords[count][i] = xCoords[count + 1][i];
                            }
                            xCoords[3][i] = Math.Round(((double)spectrumArray[i]), 2);
                            xCoord = Math.Round(((double)wavelengthArray[i]), 2);
                            yCoord = Math.Round(((xCoords[15][i] + xCoords[14][i] + xCoords[13][i] + xCoords[12][i] + xCoords[11][i] + xCoords[10][i] + xCoords[9][i] + xCoords[8][i] + xCoords[7][i] + xCoords[6][i] + xCoords[5][i] + xCoords[4][i] + xCoords[3][i] + xCoords[2][i] + xCoords[1][i] + xCoords[0][i]) / 16 * 100f / 65535f), 2);
                            list_dynamicScan[m_PairListCount].Add(xCoord, yCoord);
                        }
                    }
                }
                zedGraphControl1.Invoke(hh);
                Thread.Sleep(100);
           }
        }

解决方案 »

  1.   

    不好意思,这个忘贴了,在界面中使用一个button控件控制:
    private void toolStripButton_play_Click(object sender, EventArgs e)
            {
                if (toolStripButton_play.Enabled == true)
                {
                    toolStripButton_play.Enabled = false;
                    toolStripButton_pause.Enabled = true;
                    zedGraphControl1.GraphPane.GraphObjList.Clear();
                    bool_Isrefreshstop = false;
                }
                mythread = new Thread(refreshgraph);
                mythread.IsBackground = true;
                switch (mythread.ThreadState)
                {
                    case ThreadState.Unstarted|ThreadState .Background :
                        mythread.Start();
                        break;
                    case ThreadState.Suspended | ThreadState.Background:
                        mythread.Resume();
                        break;
                    default:
                        break;
                }
            }
      

  2.   

    一个FIFO字节缓冲  bytebuffer一个FIFO图像缓冲  imagebufferusb读取线程:向bytebuffer写数据绘图线程:从bytebuffer读数据,绘制图像,保存到imagebuffer界面:从imagebuffer读图像,显示。这个用Timer定时读取就可以了。
      

  3.   

    我也看了http://www.microsoft.com/china/MSDN/library/enterprisedevelopment/softwaredev/misMultithreading.mspx?mfr=true
    可是也没看明白
      

  4.   


    冲突只能在读取2个缓冲bytebuffer,imagebuffer时产生。只要这2个缓冲使用线程同步就不会有问题。
    使用lock就可以了。
      

  5.   

    是这句话?
      zedGraphControl1.Invoke(hh); 
      

  6.   

    参考C# WinForm开发系列 - Thread/Delegate/Event
      

  7.   

    如果我将下面这句代码屏蔽掉,则程序不会出现问题:
    spectrumArray = ((double[])wrapper.getSpectrum(0));// 此处就是读取USB设备数据. 
    而invoke这句似乎影响不大,当采集时间比较长的时候,即便不用invoke程序还是慢.
      

  8.   


    可以这么理解吧。用了Invoke,基本上就失去了多线程的意义。
      

  9.   

    就用上面说的方法实现了。
    fifo在网上搜搜,有很多。
    多线程一定要使用同步操作的。
      

  10.   

    一个fifo例子
    /*
     * 先进先出缓冲 
     * 缓冲满,丢掉后来的数据
     */
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.Collections;    public class ZDropFifo : IDisposable
        {
            #region variable
            protected Queue m_inputQueue;
            protected int 主缓冲长度 = 0;
            protected int 允许读取的起始位置 = 0;        protected byte[] 主缓冲 = null;        protected int 写指针 = 0;
            protected bool 写位置 = false;
            protected int 读指针 = 0;
            protected bool 读位置 = false;        //计算位置使用的变量
            protected int 到缓冲结尾的距离 = 0;
            protected int 剩余的字节长度 = 0;        public bool 可以读 = false;
            public int 有效数据长度 = 0;
            protected int 写入长度 = -2;
            protected int 读取长度 = -2;        int temp = 0;
            #endregion        #region public function
            public ZDropFifo(int 长度, int 起始)
            {
                m_inputQueue = new Queue();
                主缓冲长度 = 长度;
                允许读取的起始位置 = 起始;
                主缓冲 = new byte[主缓冲长度];
            }        public void Dispose()
            {
                主缓冲 = null;
                m_inputQueue = null;
            }        public int 写(byte[] 源, int 源长度)
            {
                lock (m_inputQueue)
                {
                    //Monitor.Enter(m_inputQueue);
                    //Console.WriteLine("写");
                    if (可以读 == false && 写指针 >= 允许读取的起始位置)
                        可以读 = true;                if (写位置 == 读位置)  //写指针 读指针 在同一圈
                    {
                        //计算有效数据长度
                        有效数据长度 = 写指针 - 读指针;
                        到缓冲结尾的距离 = 主缓冲长度 - 写指针;
                        剩余的字节长度 = 源长度 - 到缓冲结尾的距离;                    if (到缓冲结尾的距离 > 源长度)
                        {
                            Buffer.BlockCopy(源, 0, 主缓冲, 写指针, 源长度);
                            写指针 += 源长度;
                            //Monitor.Exit(m_inputQueue);
                            //return 源长度;
                            写入长度 = 源长度;
                        }
                        else  //写指针到缓冲结尾的距离<源长度
                        {
                            if ((读指针 + 到缓冲结尾的距离) > 源长度)
                            {
                                Buffer.BlockCopy(源, 0, 主缓冲, 写指针, 到缓冲结尾的距离);
                                Buffer.BlockCopy(源, 到缓冲结尾的距离, 主缓冲, 0, 剩余的字节长度);                            写指针 = 剩余的字节长度;
                                写位置 = !写位置;
                                //Monitor.Exit(m_inputQueue);
                                //return 源长度;
                                写入长度 = 源长度;
                            }
                            else  //读指针 + 到缓冲结尾的距离 < 源长度
                            {
                                //Monitor.Exit(m_inputQueue);
                                //return 0;
                                写入长度 = 0;
                            }
                        }
                    }
                    else  //写指针 读指针 不在同一圈
                    {
                        //计算有效数据长度
                        有效数据长度 = 主缓冲长度 + 写指针 - 读指针;
                        剩余的字节长度 = 读指针 - 写指针;                    if (剩余的字节长度 > 源长度)
                        {
                            Buffer.BlockCopy(源, 0, 主缓冲, 写指针, 源长度);
                            写指针 += 源长度;
                            //Monitor.Exit(m_inputQueue);
                            //return 源长度;
                            写入长度 = 源长度;
                        }
                        else  //写指针到读指针的字节长度 < 源长度
                        {
                            //Monitor.Exit(m_inputQueue);
                            //return 0;
                            写入长度 = 0;
                        }
                    }
                }
                return 写入长度;
            }        public int 读(byte[] 目的, int 目的长度)
            {
                //Monitor.Enter(m_inputQueue);
                lock (m_inputQueue)
                {
                    if (可以读)
                    {
                        if (写位置 == 读位置)
                        {
                            有效数据长度 = 写指针 - 读指针;
                            if ((写指针 - 读指针) > 目的长度)
                            {
                                Buffer.BlockCopy(主缓冲, 读指针, 目的, 0, 目的长度);
                                读指针 += 目的长度;
                                //Monitor.Exit(m_inputQueue);
                                //return 目的长度;
                                读取长度 = 目的长度;
                            }
                            else
                            {
                                //Monitor.Exit(m_inputQueue);
                                //return 0;
                                读取长度 = 0;
                            }
                        }
                        else
                        {
                            有效数据长度 = 主缓冲长度 + 写指针 - 读指针;
                            到缓冲结尾的距离 = 主缓冲长度 - 读指针;                        if (到缓冲结尾的距离 > 目的长度)
                            {
                                Buffer.BlockCopy(主缓冲, 读指针, 目的, 0, 目的长度);
                                读指针 += 目的长度;
                                //Monitor.Exit(m_inputQueue);
                                //return 目的长度;
                                读取长度 = 目的长度;
                            }
                            else
                            {
                                剩余的字节长度 = 目的长度 - 到缓冲结尾的距离;
                                if (剩余的字节长度 < 写指针)
                                {
                                    Buffer.BlockCopy(主缓冲, 读指针, 目的, 0, 到缓冲结尾的距离);
                                    Buffer.BlockCopy(主缓冲, 0, 目的, 到缓冲结尾的距离, 剩余的字节长度);
                                    读指针 = 剩余的字节长度;
                                    读位置 = !读位置;
                                    //Monitor.Exit(m_inputQueue);
                                    //return 目的长度;
                                    读取长度 = 目的长度;
                                }
                                else
                                {
                                    //Monitor.Exit(m_inputQueue);
                                    //return 0;
                                    读取长度 = 0;
                                }
                            }
                        }
                    }
                }
                return 读取长度;
            }        public byte[] 缓冲区
            {
                get
                {
                    return 主缓冲;
                }
            }        #endregion        protected int 加指针(int n)
            {
                if (写位置 == 读位置)
                {
                    temp = 读指针 + n;
                }
                else
                {
                    temp = 读指针 + n;
                    if (temp < 主缓冲长度)
                    {
                        //return temp;
                    }
                    else
                    {
                        temp -= 主缓冲长度;
                        //return 0;
                    }
                }
                return temp;
            }
        }
      

  11.   

    使用后台线程处理从usb设备读数据和使用异步通信
      

  12.   

    hecker728和softlove03,你们到底谁说的对啊?到底同步和异步在我这里有何差别?
      

  13.   

    mythread.IsBackground = true; 我现在的线程应该就是后台线程吧?异步通信是使用Begininvoke??
     zedGraphControl1.BeginInvoke(hh); ??这样我试过,也不行,还不如invoke呢
      

  14.   

    没看明,"while (true) " 什么时候跳出.下面我测试的代码: public partial class frmThread : Form
        {
            public frmThread()
            {
                InitializeComponent();
                Control.CheckForIllegalCrossThreadCalls = false;
            }        public delegate void PercentCompleteEventHandler(string Message, int Percent);
            event PercentCompleteEventHandler PercentComplete;        private void button1_Click(object sender, EventArgs e)
            {
                m_tspbProgressBar.Value = 0;
                m_tspbProgressBar.Minimum = 0;// 进度条 
                m_tspbProgressBar.Maximum = 100;
                m_tspbProgressBar.Visible = true;            PercentComplete = new PercentCompleteEventHandler(Step);
                ThreadStart start = new ThreadStart(DataRebateExcute);
                start.BeginInvoke(AsyncCallbackMethod,null);          
                       }        /// <summary>
            /// 数据处理
            /// </summary>
            public void DataRebateExcute() 
            {
                for (int i = 0; i < 100; i++)
                {
                    Thread.Sleep(100);
                    PercentComplete.Invoke(i.ToString(), i);
                }        }
                 
            /// <summary>
            /// 进度条调整
            /// </summary>
            public void Step(string Message, int percent) 
            {             
                m_tspbProgressBar.Value = percent;
                Application.DoEvents();
            }        /// <summary>
            /// 线程完成后回调
            /// </summary>
            /// <param name="myIAsyncResult"></param>
            public  void AsyncCallbackMethod(System.IAsyncResult myIAsyncResult)
            {
                m_tspbProgressBar.Visible = false;
                MessageBox.Show("成功", this.Text,
                MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;   
            }
        }
      

  15.   

    while(true)的目的是为了使这个线程一直循环往复的去接收USB设备的数据,直到应用程序退出.此处的接收数据是主动接收,并非下位机不停的往上传数据.
    spectrumArray = ((double[])wrapper.getSpectrum(0));// 只有这句代码才使下位机回传数据.
      

  16.   

    while(true)过程里加上Application.DoEvents();试下
      

  17.   

    To iStartSoft :我将refreshgraph方法改成如下,情况照旧.
    private void refreshgraph()
            {            while (true)
                {
                    Application.DoEvents();
                    spectrumArray = ((double[])wrapper.getSpectrum(0));
                    Thread.Sleep(100);
                }
            }
      

  18.   

    用线程池,资源共享有冲突可以使用自定义的Message
      

  19.   

    我将OmniDriver.CCoWrapperClass wrapper=newOmniDriver.CCoWrapperClass(); 这句代码放到线程中,问题得到解决.如下:private void refreshgraph() 
            { 
                OmniDriver.CCoWrapperClass wrapper=newOmniDriver.CCoWrapperClass(); 
                while (true) 
                { 
                    spectrumArray = ((double[])wrapper.getSpectrum(0)); 
                    Thread.Sleep(100); 
                } 
            } 请问是何原因?我理解如果OmniDriver.CCoWrapperClass wrapper=newOmniDriver.CCoWrapperClass(); 在主线程中,而wrapper.getSpectrum()采用委托的方式的话,就可能会导致UI界面锁定的现象.不知有谁能够解释此原因?
      

  20.   

    设置CheckForIllegalCrossThreadCalls不知会如何? InitializeComponent();
     Control.CheckForIllegalCrossThreadCalls = false;