【问题标题】:Updating progress bar from a threadpool c#从线程池c#更新进度条
【发布时间】:2011-10-05 05:33:52
【问题描述】:

我试图使用多线程处理一些数据,其中我使用线程池来生成等于内核数的线程(仅限于 .NET 2.0 到 3.5,因此不能使用 TPL)。

我的所有线程都在我的数据的不同部分执行相同的函数。

我的问题是我无法从线程池的线程更新进度条。找到了invoke和Background worker之类的解决方案,但是不太明白怎么用,请帮我看看怎么用。

我的代码看起来像

 private static float[] inpdat=new float[1000];//The input array to process
 //The spawned threads
 public void dowork(object o) 
 {
    int np = (int)o;
    for(int i=np;i<inpdat.length;i=i+Environment.ProcessorCount)
    {
         //do some processing
         if(np==0)
          {
              //update progress bar here
          }
    }
 }


    //The main thread
    for (int npou = 0; npou < numproc; npou++)
    {
        resetEvents[npou] = new ManualResetEvent(false);
        ThreadPool.QueueUserWorkItem(new WaitCallback(dowork), npou);
        PetrelLogger.InfoOutputWindow("manual reset event set");
    }

速度对我来说是最重要的,所以如果跨线程调用占用最少的时间会非常有帮助。 谢谢

【问题讨论】:

  • “使用线程池生成与内核数相等的线程” - 您很少需要自己明确地优化线程数。线程池就是为此而设计的。

标签: c# progress-bar threadpool


【解决方案1】:

这是一个例子:

ThreadPool.QueueUserWorkItem(new WaitCallback(o =>
    {
        // worker method implementation
        .....
        progressBar1.Invoke(new MethodInvoker(() => progressBar1.Value = 20));
    }));

【讨论】:

  • 我的算法和表单属于不同的类。无法消除该限制。
  • 你的意思是你不能直接访问 ProgressBar 控件,因为它在不同的窗体上并且线程池在另一个类中调用?
  • 在这种情况下,您需要以某种方式在您的班级中提供表单参考。通过 Form 中的 internal/public 属性使 ProgressBar 控件可访问可以解决您的问题。
【解决方案2】:

您可以通过更新用户控件来做一些事情,例如进度条。 添加您的表单作为输入参数,或为结果添加一些回调接口,您的表单将实现:

interface IMyCallback
{
    void Progress(int progress);
}

在表单实现中添加以下代码:

void Progress(int Progress)
{
    if(this.InvokeRequired)
    {
        this.BeginInvoke(new ParametrizedThreadStart(Inv_Progress), Progress);
    }
    else
    {
        Inv_Progress(Progress);
    }
}

void Inv_Progress(object obj)
{
    int progress = obj as int;
    // do your update progress bar work here

}

现在您可以执行以下操作:

public void dowork(object o) 
 {
    int np = (int)o;
    for(int i=np;i<inpdat.length;i=i+Environment.ProcessorCount)
    {
         //do some processing
         if(np==0)
          {
              myCallback.Progress(0);
          }
    }
 }

【讨论】:

    【解决方案3】:

    标准调用可能是最简单的,您可以使用匿名委托使其更简洁。

    int n = 5;
    myProgressBar.Invoke(
        delegate
        {
            myProgressBar.Value = n;
        }
    );
    

    请记住,在某些情况下(例如,在一个线程中循环使用此委托),您可能需要声明一个委托并将值作为参数传递给它。如果你不这样做,你可能会对当地人产生奇怪的行为。使用匿名方法和Action 类也是如此。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-30
      • 2011-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-29
      • 1970-01-01
      相关资源
      最近更新 更多