我正在尝试一些QueuedBackgroundWorker
类,我发现here。它运作良好,除了我想知道如何等待所有排队的工人完成工作?例如,如果用户关闭程序,我希望程序等待所有工人完成并关闭。等待所有排队的BackgroundWorker完成?
我尝试了GUI线程做这样的事情,但它只是似乎要禁止:
try
{
while (myWorkerQueue.Queue.Count > 0) ;
}
catch (InvalidOperationException)
{
}
也试过while(myWorkerQueue.Queue.Peek() != null)
,得到了相同的结果。
代码QueuedBackgroundWorker
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;
/// <summary>
/// This is thread-safe
/// </summary>
public class QueuedBackgroundWorker
{
#region Constructors
public QueuedBackgroundWorker() { }
#endregion
#region Properties
Queue<object> Queue = new Queue<object>();
object lockingObject1 = new object();
public delegate void WorkerCompletedDelegate<K>(K result, Exception error);
#endregion
#region Methods
/// <summary>
/// doWork is a method with one argument
/// </summary>
/// <typeparam name="T">is the type of the input parameter</typeparam>
/// <typeparam name="K">is the type of the output result</typeparam>
/// <param name="inputArgument"></param>
/// <param name="doWork"></param>
/// <param name="workerCompleted"></param>
public void RunAsync<T,K>(Func<T, K> doWork, T inputArgument, WorkerCompletedDelegate<K> workerCompleted)
{
BackgroundWorker bw = GetBackgroundWorker<T,K>(doWork, workerCompleted);
Queue.Enqueue(new QueueItem(bw, inputArgument));
lock (lockingObject1)
{
if (Queue.Count == 1)
{
((QueueItem)this.Queue.Peek()).RunWorkerAsync();
}
}
}
/// <summary>
/// Use this method if you don't need to handle when the worker is completed
/// </summary>
/// <param name="doWork"></param>
/// <param name="inputArgument"></param>
public void RunAsync<T,K>(Func<T, K> doWork, T inputArgument)
{
RunAsync(doWork, inputArgument, null);
}
private BackgroundWorker GetBackgroundWorker<T, K>(Func<T, K> doWork, WorkerCompletedDelegate<K> workerCompleted)
{
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = false;
bw.WorkerSupportsCancellation = false;
bw.DoWork += (sender, args) =>
{
if (doWork != null)
{
args.Result = (K)doWork((T)args.Argument);
}
};
bw.RunWorkerCompleted += (sender, args) =>
{
if (workerCompleted != null)
{
workerCompleted((K)args.Result, args.Error);
}
Queue.Dequeue();
lock (lockingObject1)
{
if (Queue.Count > 0)
{
((QueueItem)this.Queue.Peek()).RunWorkerAsync();
}
}
};
return bw;
}
#endregion
}
public class QueueItem
{
#region Constructors
public QueueItem(BackgroundWorker backgroundWorker, object argument)
{
this.BackgroundWorker = backgroundWorker;
this.Argument = argument;
}
#endregion
#region Properties
public object Argument { get; private set; }
public BackgroundWorker BackgroundWorker { get; private set; }
#endregion
#region Methods
public void RunWorkerAsync()
{
this.BackgroundWorker.RunWorkerAsync(this.Argument);
}
#endregion
}
把UI线程进入一个“while”循环就像你看到前面是一个真正的糟糕的主意,因为现在UI线程不能再做任何UI工作(简单来说)。你的后台线程多久了?他们中的任何人使用Invoke或BeginInvoke来进行UI更新。更好的解决方案将取决于你的后台线程正在做什么。 – Christoph
他们正在做一些背景计算和数据库读取/结果保存。每个工人通常不到几分钟。 – user17753
“等待”是什么意思?如果你运行while(myWorkerQueue.Queue.Count> 0);在UI线程上,它阻塞,那么你正在等待 –