最近遇到一个项目,需要开发一个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);
}
}
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);
}
}
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个缓冲bytebuffer,imagebuffer时产生。只要这2个缓冲使用线程同步就不会有问题。
使用lock就可以了。
zedGraphControl1.Invoke(hh);
spectrumArray = ((double[])wrapper.getSpectrum(0));// 此处就是读取USB设备数据.
而invoke这句似乎影响不大,当采集时间比较长的时候,即便不用invoke程序还是慢.
可以这么理解吧。用了Invoke,基本上就失去了多线程的意义。
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;
}
}
zedGraphControl1.BeginInvoke(hh); ??这样我试过,也不行,还不如invoke呢
{
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;
}
}
spectrumArray = ((double[])wrapper.getSpectrum(0));// 只有这句代码才使下位机回传数据.
private void refreshgraph()
{ while (true)
{
Application.DoEvents();
spectrumArray = ((double[])wrapper.getSpectrum(0));
Thread.Sleep(100);
}
}
{
OmniDriver.CCoWrapperClass wrapper=newOmniDriver.CCoWrapperClass();
while (true)
{
spectrumArray = ((double[])wrapper.getSpectrum(0));
Thread.Sleep(100);
}
} 请问是何原因?我理解如果OmniDriver.CCoWrapperClass wrapper=newOmniDriver.CCoWrapperClass(); 在主线程中,而wrapper.getSpectrum()采用委托的方式的话,就可能会导致UI界面锁定的现象.不知有谁能够解释此原因?
Control.CheckForIllegalCrossThreadCalls = false;