【问题标题】:C# BackgroundWorker ReportProgress Behaving StrangelyC# BackgroundWorker ReportProgress 行为异常
【发布时间】:2010-07-14 16:15:24
【问题描述】:

我的backgroundWorker使用ReportProgress更新了一个漫长的过程的ProgressPercentage。在ProgressChanged ProgressPercentage 的三个条目中有两个是零,而ProgressChanged 的每三个条目ProgressPercentage 是我所期望的。这就像发条一样发生;这是非常可重复的。下面是一些演示我的设置的简化代码(为了减少长度,我删除了错误处理代码):

AutoResetEvent areProgressChanged = new AutoResetEvent(false);

  private void backgroundWorkerProgram_DoWork(object sender, DoWorkEventArgs e)
  {
     bool bRetVal = true;
     int iRetries = 3;
     int iProgress = 0;

     // Repeat Program message and entire sequence until programming
     // is complete or Retries reaches 0...
     do
     {
        bRetVal = Program();

        this.eBgwProgramStatus = BgwProgramStatus.BUSY;
        bRetVal = this.WaitForReceive(SHORT_ACK_WAIT, backgroundWorkerProgram);

        switch (this.eCommsRsp)
        {
           case CommsRsp.ACK:
              this.eBgwProgramStatus = BgwProgramStatus.BUSY;
              iRetries = 3;
              break;
        }
     }
     while ((!backgroundWorkerProgram.CancellationPending)
        && (!bRetVal) && (iRetries > 0));

     // Repeat Write and Data message until programming is complete...
     do
     {
        this.eBgwProgramStatus = BgwProgramStatus.BUSY;
        bRetVal = Write();

        this.eBgwProgramStatus = BgwProgramStatus.BUSY;
        bRetVal = this.WaitForReceive(SHORT_ACK_WAIT, backgroundWorkerProgram);

        switch (this.eCommsRsp)
        {
           case CommsRsp.ACK:
              this.eBgwProgramStatus = BgwProgramStatus.BUSY;
              bRetVal = SendData(pData_c);
              break;

           default:
           case CommsRsp.NACK:
           case CommsRsp.NONE:
              this.eBgwProgramStatus = BgwProgramStatus.NO_ACK_RXD;
              iRetries--;
              bRetVal = false;
              break;
        }

        this.eBgwProgramStatus = BgwProgramStatus.BUSY;
        bRetVal = this.WaitForReceive(SHORT_ACK_WAIT, backgroundWorkerProgram);

        switch (this.eCommsRsp)
        {
           case CommsRsp.ACK:
              this.eBgwProgramStatus = BgwProgramStatus.BUSY;
              iProgress = (this.iProgramSize * 100) / PIC32.ProgMem.Length;
              this.backgroundWorkerProgram.ReportProgress(iProgress);
              this.areProgressChanged.WaitOne();
              iRetries = 3;
              this.iRow++;
              break;

           default:
           case CommsRsp.NACK:
           case CommsRsp.NONE:
              this.eBgwProgramStatus = BgwProgramStatus.NO_ACK_RXD;
              iRetries--;
              bRetVal = false;
              break;
        }
     }
     while ((!backgroundWorkerProgram.CancellationPending)
        && (iRetries > 0)
        && ((!bRetVal) || (this.eBgwProgramStatus == BgwProgramStatus.BUSY)));
  }

  private void backgroundWorkerProgram_ProgressChanged(object sender, ProgressChangedEventArgs e)
  {
     string sProgressPercentage = e.ProgressPercentage.ToString() + "%";

     // Report progress.
     this.labelPercentComplete.Visible = true;
     this.labelPercentComplete.Text = sProgressPercentage;
     this.toolStripStatusLabel.Text = this.sProgramming + sProgressPercentage;
     this.textBoxData.AppendText(this.tBusText.ToString());
     this.textBoxStatus.AppendText(this.tStatusText.ToString());
     this.tBusText.Remove(0, this.tBusText.Length);
     this.tStatusText.Remove(0, this.tStatusText.Length);
     this.areProgressChanged.Set();
  }

(我为长度道歉,但有人要求。)无论有没有AutoResetEvent,都会表现出相同的行为。有没有人对为什么会发生这种情况有任何想法?谢谢。

附加细节

如果我在this.backgroundWorkerProgram.ReportProgress(iProgress); 上设置断点,我可以看到iProgress 按预期递增(慢慢地,在几个间隔内,例如 0,0,0,1,1,1,2,2,2,3 ,3,3 等)。然后,如果我将断点移动到string sProgressPercentage = e.ProgressPercentage.ToString() + "%";e.ProgressPercentage 的值与iProgress 的传递值不匹配。我得到的是 0,0,0,0,1,0,0,2,0,0,3,0,0 等。

【问题讨论】:

  • 为什么不给我们一个简短而完整的例子来说明问题,而不是伪代码呢?这样可以更轻松地为您提供帮助。
  • 这不是 Bgw 的正常行为,因此您的(真实)代码中一定有某些东西导致了它。所以我同意乔恩的观点:发布一个小型演示程序。您很可能会在此过程中发现问题。
  • 您是否在调试器中单步执行过这段代码?看起来您只是在非常特定的条件下才调用ReportProgress。此外,您传递给此方法的值 (iProgress) 是计算的结果:(this.iProgramSize * 100) / PIC32.ProgMem.Length,不管它是什么。作为一个局外人,我不清楚是什么让你如此确定这个值有时不会为零。
  • PIC32.ProgMem.Length 是应用程序此时的固定值;也就是说,它只能通过用户干预来更改,并且在此代码运行时相关的用户控件被禁用。随着序列的进行,iProgramSize 从零递增到PIC32.ProgMem.Length。我正在考虑使用全局变量进行快速修复。我知道,它不漂亮,但这是更重要的事情。

标签: c# backgroundworker


【解决方案1】:

iProgramSize 和 PIC32.ProgMem.Length 的前几个值是什么?

例如,如果 PIC32.ProgramMem.Length 为 300,iProgramSize 为 1、2、3、4、5、6 等,则完成百分比应为 0、0、1、1、1、2 等。

另外,您确定 ProgressPercentage 传递不正确,可能是标签控件没有正确更新/刷新?

【讨论】:

  • iProgramSize 从 0 开始递增到 PIC32.ProgramMem.Length,在这部分应用中是一个固定值,大约 512K。如果我在this.backgroundWorkerProgram.ReportProgress(iProgress); 上设置断点,我可以看到iProgress 按预期递增(慢慢地,在几个间隔内,例如 0,0,0,1,1,1,2,2,2,3,3, 3等)。然后,如果我将断点移动到string sProgressPercentage = e.ProgressPercentage.ToString() + "%";e.ProgressPercentage 的值与iProgress 的传递值不匹配。我得到的是 0,0,0,0,1,0,0,2,0,0,3,0,0 等。
  • 奇怪。我假设 e.ProgressPercentage 以 98,0,0,99,0,0,100 之类的值结尾,如果 e.ProgressPercentage 为零,则可能的解决方法是不更新标签。错误值(零)的数量是否与重复输入的数量相关,即如果您将 iProgress 更改为 = (this.iProgramSize * 50) / PIC32.ProgMem.Length,这是否意味着您最终会在值正确吗?
  • 显然,这个问题是在优化应用程序的可伸缩性时以某种方式引入的。我终于让程序再次达到“稳定”点,重新测试,问题就像它看起来一样神秘地消失了。我对你的回复投了赞成票,因为你对我的问题提出了一些批判性的思考,试图提供帮助,而不仅仅是驳回它。赞一个!
【解决方案2】:

显然,在优化应用程序以实现可伸缩性时,不知何故引入了这个问题。我终于让程序再次达到“稳定”点,重新测试,问题就和它看起来一样神秘地消失了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多