问题
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.
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());
}
}
}
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.
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.
回答1:
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:
- the work periodically checks some "abort" flag and terminates itself cleanly
- you abort the entire 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.
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).
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.
来源:https://stackoverflow.com/questions/16375645/how-to-abort-a-list-of-tasks-from-the-outside