我尝试使用多线程处理一些数据,其中我使用线程池生成等于内核数量的线程(限于.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");
}
速度对我来说至关重要,如果跨线程调用占用最少的时间,那将非常有用。 谢谢
答案 0 :(得分:1)
以下是一个例子:
ThreadPool.QueueUserWorkItem(new WaitCallback(o =>
{
// worker method implementation
.....
progressBar1.Invoke(new MethodInvoker(() => progressBar1.Value = 20));
}));
答案 1 :(得分:0)
您可以使用进度条更新用户控件。 添加表单作为输入参数,或为结果添加一些回调接口,表单将实现:
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);
}
}
}
答案 2 :(得分:0)
标准调用可能最简单,您可以使用匿名委托使其更清晰。
int n = 5;
myProgressBar.Invoke(
delegate
{
myProgressBar.Value = n;
}
);
请记住,在某些情况下(例如,在一个线程内循环使用此委托),您可能需要声明委托并将值作为参数传递给它。如果不这样做,您可能会对当地人产生奇怪的行为。这也是使用匿名方法和Action
类的情况。