0

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

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

到目前为止,我拥有的基本模板是:

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 实现中编写额外的代码。

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

4

1 回答 1

2

中止正在运行的代码可以通过两种方式完成(好吧,有点 3,如果你包括“它永远不会从要做的事情队列中开始”,我怀疑这已经发生在取消的任务中),其中只有一种是理智的:

  • 工作定期检查一些“中止”标志并干净地终止自己
  • 你中止整个线程

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

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

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

于 2013-05-04T15:09:59.487 回答