您在我的另一个答案的评论之一中提到了一个链接,看起来该链接描述了如何使其可取消。我已经调整了我的示例来支持这一点:
private Dictionary<Guid, TaskTracker> _taskMap = new Dictionary<Guid, TaskTracker>();
private void OnButton1Click(object sender, EventArgs eventArgs)
{
TaskTracker taskTracker = new TaskTracker(Guid.NewGuid(), OnDoWork);
_taskMap.Add(taskTracker.Identity, taskTracker);
taskTracker.Start();
}
private void OnDoWork(CancellationToken token)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(100); // Do some work, checking if cancel requested every once in a while
if (token.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
}
}
private void OnButton2Click(object sender, EventArgs eventArgs)
{
Guid identity = _taskMap.Count > 0 ? _taskMap.First().Value.Identity : default(Guid); // find some way to get the desired task
TaskTracker taskTracker;
if (_taskMap.TryGetValue(identity, out taskTracker))
{
taskTracker.TaskExiting += OnTaskExiting;
taskTracker.Stop();
}
}
private void OnTaskExiting(object sender, EventArgs eventArgs)
{
TaskTracker taskTracker = (TaskTracker)sender;
taskTracker.TaskExiting -= OnTaskExiting;
_taskMap.Remove(taskTracker.Identity);
Console.WriteLine("Time ellapsed for No partitioning at all version {0}ms , thread id was {1}", taskTracker.Stopwatch.ElapsedMilliseconds, Task.CurrentId);
}
private void OnButton3Click(object sender, EventArgs eventArgs)
{
Guid identity = _taskMap.Count > 0 ? _taskMap.First().Value.Identity : default(Guid); // find some way to get the desired task
TaskTracker taskTracker;
if (_taskMap.TryGetValue(identity, out taskTracker))
{
taskTracker.TaskExiting += OnTaskExiting;
taskTracker.Cancel();
}
}
这是 TaskTracker 类:
public class TaskTracker
{
private readonly Action<CancellationToken> OnDoWork;
private readonly CancellationTokenSource TokenSource;
private readonly CancellationToken Token;
private bool _isRunning;
private Task _task;
public TaskTracker(Guid identity, Action<CancellationToken> onDoWork)
{
TokenSource = new CancellationTokenSource();
Token = TokenSource.Token;
Identity = identity;
OnDoWork = onDoWork;
}
public readonly Guid Identity;
public readonly Stopwatch Stopwatch = new Stopwatch();
public event EventHandler TaskExiting;
public void Start()
{
_isRunning = true;
_task = Task.Factory.StartNew(
() =>
{
Stopwatch.Start();
try
{
while (_isRunning)
{
OnDoWork(Token);
}
}
finally
{
Stopwatch.Stop();
if (TaskExiting != null)
{
TaskExiting(this, EventArgs.Empty);
}
}
}, Token
);
}
public void Stop(bool waitForTaskToExit = false)
{
if (_task == null)
{
throw new InvalidOperationException("Task hasn't been started yet");
}
_isRunning = false;
if (waitForTaskToExit)
{
_task.Wait();
}
_task = null;
}
public void Cancel()
{
if (_task == null)
{
throw new InvalidOperationException("Task hasn't been started yet");
}
_isRunning = false;
TokenSource.Cancel();
_task = null;
}
}
基本上,在您的“工人”中,您将检查令牌是否表明它正在被取消,如果是,请进行一些清理,然后在令牌上调用 ThrowIfCancellationRequested 方法以中断。