私の他の回答からのコメントの1つにリンクについて言及されましたが、そのリンクはキャンセル可能にする方法を説明しているようです。私はこれをサポートするために私の例を適応させました:
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を呼び出してブレークアウトします。