假设我有两个线程。在一个线程上,我正在执行一系列作业。在另一个线程上,我正在等待用户输入来控制这些作业(即,跳到下一个作业)。例如(伪C#):
public class Worker {
public List<Job> Jobs { get; set; }
public Worker(Controller anotherThread) {
anotherThread.SkipJobRequested += OnSkipJobRequested;
}
public DoWork() {
foreach (Job job in Jobs) {
// Do various work...
}
}
// Event that fires on Controller thread
public void OnSkipJobRequsted(Object sender, EventArgs args) {
// Somehow skip to the next job
}
}
我不知道该如何应付跳槽的问题。我想到的一种可能性是,当请求跳过时,我会设置一个实例变量(如IsSkipRequested
),并在DoWork()
内的各个节点对其进行检查。
是否存在我可以用来处理此事件的其他模式?
另一种模式是.Net类BackgroundWorker,它似乎适合您的目的。您可以使Job成为BackgroundWorker的子类,然后循环使用。不同的是BackgroundWorker不知道您的UI线程,只知道是否请求了取消。
在这种模式中,UI线程将调用CancelAsync,然后您的DoWork方法将每隔一段方便的时间检查CancellationPending以决定是否继续。对于RunWorkerCompleted事件处理程序中的下一个作业,您可以调用runWorkerSync。
另一个建议是(您已经在上面提到了这一点)如果您将List<Jobs>
设置为Queue<Jobs>
,并且DoWork不执行foreach来维护对象中的当前执行作业,而是可以在准备好处理时将每个项目排成队列。
任务并行库允许您指定一个取消令牌(尽管您可能必须将其传递给作业执行代码,并在其中处理取消),当按下skip时,您可以调用RequestCancellation,并从队列中启动下一个作业。此外,当启动新任务时,您可以指定完成时要执行的操作,这将允许您将任务按顺序链接在一起,并在需要时跳过任务。下面是一个没有取消令牌的示例:
_currentJob = Jobs.DeQueue();
Task.Factory.StartNew(() => {_currentJob.execute();},
() =>
{
//On task completion logic
ExecuteNextJobFromQueue();
}
请注意,如果作业正在执行多个任务,而不是一个大的阻塞任务,则这种方法可能最有效,因为您需要在作业执行期间检查是否取消。