我刚刚用C#创建了一个应用程序,它使用一个线程来轮询UART以获取接收事件。 如果接收到数据,则在我的主线程(GUI)中触发一个事件,并通过PerformStep()方法控制进度条(当然,我之前已经相应地设置了Max值)。 为了处理跨线程,使用以下表达式调用PerformStep:
this.Invoke((Action)delegate{progressBar2.PerformStep();})
运行此应用程序时,进度条从未达到其最终值。它停在80%。在调试并停止在上述行时,使用单步操作一切正常。我不知道发生了什么!
在主线程上启动读取线程:
pThreadWrite = new Thread(new ThreadStart(ReadThread));
pThreadWrite.Start();
读取线程:
private void ReadThread()
{
while(1)
{
if (ReceiveEvent)
{
FlashProgressBar();
}
}
}
在主线程中触发的事件:
private void FlashProgressBar()
{
this.Invoke((Action)delegate { progressBar2.PerformStep();});
}
这只是我代码的简化版本。
看起来内部进度比视觉进度更快。
编辑2: 好的,我想我明白了。问题在于使用invoke方法处理跨线程。我在SO上找到了这句话:
不,至少对于Windows来说,这是任何UI的基础。Windows Forms中的消息架构并不新鲜,即使是C++应用程序在Windows中也是这样。如果您正在尝试更新进度条或其他内容,您不应该跨线程调用。而是使用交错写入到进度变量,UI线程以一定间隔读取。
和
是的,可能会有任意长的延迟。Invoke通过向目标控件发送Windows消息工作,因此只有在目标线程泵出消息时才会被处理。如果线程已经在处理消息,并且该处理需要时间,则可能会在线程泵出下一个消息并处理Invoke之前存在可感知的延迟。
所以我需要找到另一种解决方案,例如等待BeginInvoke方法完成!
编辑:
如果我插入一些thread.sleep()语句,似乎可以工作。可能是计时器使用有问题。该计时器由读取线程启动,如果超过事件,则触发:
读取线程:
private void ReadThread()
{
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
UInt32 numBytesAvailable = 0;
while (true)
{
ftStatus = myFtdiDevice.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
// read data and start timer
TimeoutWaitForAckn.Start();
}
}
}
如果计时器超过了设定时间,事件就会被触发。使用sleep语句可以很好地实现这一点:
private void Timeout_Handler(object sender, System.Timers.ElapsedEventArgs e)
{
Thread.Sleep(300);
Trigger_ReportBufferReceivedEvent(ReceiveBuffer);
}
关于线程、定时器和事件,有没有已知的问题?使用的是System.Timers.Timer。
PerformStep
会按照ProgressBar
的Step
属性所给定的数量进行推进,而该属性默认为10
而不是1
? - Timwi