Progressbar表现得很奇怪

时间:2011-02-12 22:43:57

标签: c# winforms multithreading progress-bar

我刚刚在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: 好吧,我想我是git它。问题是 invoke 方法来处理交叉线程。我在SO上找到了这句话:

不,至少就Windows来说,它是任何用户界面的基础。 Windows窗体中的消息体系结构并不是什么新鲜事,即使C ++应用程序在Windows中运行也是如此。如果您正在尝试更新进度条或其他内容,则不应跨线程调用。而是使用互锁写入UI线程以特定间隔读取的进度变量。

是的,可能会有任意长的延迟。调用通过向目标控件发送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();
            }
        }
    }

然后,如果计时器超过事件被触发。睡眠声明指出它:

    private void Timeout_Handler(object sender, System.Timers.ElapsedEventArgs e)
    {
        Thread.Sleep(300);
        Trigger_ReportBufferReceivedEvent(ReceiveBuffer);
    }

是否存在考虑线程,计时器和事件的已知问题?使用System.Timers.Timer。

1 个答案:

答案 0 :(得分:0)

我认为我们无法帮助您处理我们无法编译或运行的代码片段,并且不知道您的其他应用程序。

我试图重现你描述的问题,我担心它不会发生。我有posted my code here in case you want to try it too(它实际上和你的代码一样)。代码显示带有进度条和按钮的表单。单击按钮,进度条会在10秒内一直上升到100%。一旦到达终点,Debugger.Break()就会触发。

如果您可以将上述代码更改为实际重现问题的代码,并将其作为自包含示例发布,那么我们将能够为您提供帮助。