如何从外部中止任务列表

时间:2013-05-04 15:00:19

标签: c# multithreading .net-4.5

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

目标是能够从这些类继承,只需要担心实现CreateWorker和DoWork方法。用户界面将调用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的方法。

1 个答案:

答案 0 :(得分:2)

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

  • 工作会定期检查一些“中止”标志并彻底终止
  • 你中止整个帖子

第一个是你应该做什么;在大多数情况下,它工作正常。第二个实际上从来都不是一个好主意。你甚至应该考虑这个问题的唯一一次是你的整个过程如此极端恶劣,以至于你只想尽快把它(以及它的痛苦)放下来。在中止线程后,您很可能将系统置于不可恢复的位置,因此绝不应该将其用于大多数理智的操作。另外:您需要引用所涉及的每个Thread,这是您没有的。

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

然而,通常首选来正式检查取消并报告您已取消,以便可以维护任务的状态。我猜你也可以从catch块执行此操作。