如何从外部中止任务列表 [英] How to abort a list of tasks from the outside

查看:22
本文介绍了如何从外部中止任务列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 .net 4.5 中的线程模型(或一般的线程)仍然很陌生.我正在尝试构建一组抽象类,以实现一个用于多线程处理一系列类似任务的框架.规则是输入的第一行说明集合中有多少问题,接下来的行包含每个问题的输入.一组输入的输入行数可能因一个任务而异,但对于给定类型的问题通常是一致的.每个问题的输出都是一行文本.

I am still fairly new to the threading model in .net 4.5 (or threading in general for that matter). I am trying to build a set of abstract classes in order to implement a framework for multithreading a series similar tasks. The rules are that the first line of the input tells how many problems are in the set, and the following lines contain the input for each problem. How many lines of input make up a set can vary from one task to the next, but are normally consistent for a given type of problem. Each problem is to have a single line of text as its output.

目标是能够继承这些类,只需要担心实现 CreateWorker 和 DoWork 方法.UI 将调用 ProcessInput 来开始工作,并调用 WriteOutput 来列出结果.

The goal is to be able to inherit from these classes and only have to worry about implementing the CreateWorker and DoWork methods. The UI will call ProcessInput to get things started, and WriteOutput to list off the results.

我目前拥有的基本模板是:

The basic template I have so far is:

public abstract class Wrapper
{
    protected int N;
    protected WorkerBase[] ProblemSet;
    protected List<Task> Tasks;

    public virtual void ProcessInput(TextReader input)
    {
        string Line = input.ReadLine();
        N = int.Parse(Line);
        ProblemSet = new WorkerBase[N];
        Tasks= new List<Task>(N);
        for (int index = 0; index < N; index++)
        {
            WorkerBase T = CreateWorker(input);
            Tasks.Add(T.DoWorkAsync());
            ProblemSet[index] = T;
        }
    }

    public virtual bool WriteOutput(TextWriter outputStream, int timeout)
    {
        bool Complete = Task.WaitAll(Tasks.ToArray(), timeout);

        for (int index = 0; index < N; index++)
        {
            outputStream.WriteLine(ProblemSet[index].Result);
        }

        return Complete;
    }

    protected abstract WorkerBase CreateWorker(TextReader inputStream);
    protected abstract class WorkerBase
    {
        public string Result
        {
            get;
            protected set;
        }
        protected abstract void DoWork();
        public Task DoWorkAsync()
        {
            return Task.Run(() => DoWork());
        }
    }
} 

按原样,这符合我的要求.但是现在我想向 Wrapper 类添加中止功能,它能够停止所有线程.所以问题是,如果单击取消按钮,我如何将中止功能工作到这个结构中,以便我的 UI 可以中止进程?最好无需在 DoWork 实现中编写额外的代码.

As is, this is meeting my requirements. But now I would like to add abort functionality to the Wrapper class which is capable of halting all of the threads. So the question is, how do I work the abort functionality into this structure in such a way that my UI can abort the process if a cancel button is clicked? Preferably without having to write extra code in the DoWork implementation.

我发现了传入取消令牌以中止任务的模式,但是我发现的每个版本都要求 DoWork 检查令牌的状态并中止自身.我真的想要一种从方法外部中止 DoWork 的方法.

I have found patterns which pass in a cancelation token in order to abort the task, but every version I have found would require that DoWork check the state of the token and abort itself. I really want a way to abort DoWork from outside the method.

推荐答案

中止正在运行的代码可以通过两种方式完成(好吧,如果您包括它永远不会从待办事项队列中开始",我就被取消的任务已经发生了怀疑),其中只有一个是正常的:

Aborting running code can be done in two ways (well, kinda 3 if you include "it never gets started from the queue of things to do", which I suspect already happens for cancelled tasks), only one of which is sane:

  • 工作会定期检查一些中止"标志并干净地自行终止
  • 您中止了整个线程

首先是你应该做什么;在大多数情况下,它工作正常.第二个几乎从来都不是一个好主意.您唯一应该考虑的情况是,您的整个过程已经病入膏肓,以至于您只想尽快放下(并摆脱痛苦).中止线程后,您很有可能将系统置于不可恢复的位置,因此永远不应将其用于大多数理智的操作.另外:您需要对所涉及的每个 Thread 进行引用,而此处没有.

the first is what you should be doing; in most cases it works fine. The second is virtually never a good idea. The only time you should even consider this is when your entire process is so terminally ill that you just want to put it down (and out of its misery) as fast as possible. After aborting threads, there's a fair chance that you've left the system in an irrecoverable position, so this should never be used for most sane operations. Also: you'd need to have a reference to each Thread involved, which you don't have here.

所以:剩下第一种情况.坦率地说,我认为你应该在这里查看标志.但是,如果您的工作人员需要定期从某处获取值,另一种可以很好地工作的方法是让所有输入属性/方法/等在那里进行检查,并且引发一个众所周知的异常,即您的工作人员在访问 foo.Count(或类似的)时可能会得到异常.

So: that leaves the first case. Frankly, I think you should just get and check the flags here. However, another approach that can work well if your worker needs to periodically get values from somewhere, is to have all the input properties / methods / etc do the check there, and raise a well-known exception, i.e. your worker might get the exception when it is just accessing foo.Count (or similar).

但是,通常最好正式检查取消并报告您已取消,以便维护任务的状态.不过,我想你也可以从 catch 块中做到这一点.

It is however, generally preferable to formally check for cancellation and report that you cancelled, so that the status of the task can be maintained. I guess you could also do this from a catch block, though.

这篇关于如何从外部中止任务列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆