[英]How to synchronize TPL Tasks, by using Monitor / Mutex / Semaphore? Or should one use something else entirely?
[英]How to monitor and stop running tasks separately using tpl
我不熟悉並行編程和c#中的tpl,我正在進行以下測試,以便了解任務的工作原理。 每次單擊button1並觸發有界方法時,都會啟動一個新任務。 當我單擊button_2時,所有任務都將退出循環,我將獲得所有任務和任務ID的時間。
那么有沒有辦法在他們在任務池中工作時監視這些任務,所以如果我希望單獨使用任務ID,我可以阻止它們?
Boolean stopprogramm = false;
private void button1_Click(object sender, EventArgs e)
{
Task timerTask1 = Task.Factory.StartNew(() =>
{
Stopwatch watch = new Stopwatch();
watch.Start();
while (stopprogramm == false)
{
//Do some work
}
Console.WriteLine("time ellapsed for No partitioning at all version {0}ms , thread id was {1}", watch.ElapsedMilliseconds, Task.CurrentId);
watch.Stop();
});
}
private void button2_Click(object sender, EventArgs e)
{
stopprogramm = true;
}
像這樣的東西可以工作。
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.Run();
}
private void OnDoWork()
{
// Do some work
}
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);
// do what you want with the timings
}
任務的類是這樣的:
public class TaskTracker
{
private readonly Action OnDoWork;
private Task _task;
private bool _isRunning = true;
public TaskTracker(Guid identity, Action onDoWork)
{
Identity = identity;
OnDoWork = onDoWork;
}
public readonly Guid Identity;
public readonly Stopwatch Stopwatch = new Stopwatch();
public event EventHandler TaskExiting;
public void Run()
{
Task _task = Task.Factory.StartNew(
() =>
{
Stopwatch.Start();
try
{
while (_isRunning)
{
OnDoWork();
}
if (TaskExiting != null)
{
TaskExiting(this, EventArgs.Empty);
}
}
finally
{
Stopwatch.Stop();
}
}
);
}
public void Stop()
{
_isRunning = false;
// wait for task to exit?
_task = null;
}
}
您需要填寫空白,意味着跟蹤任務並在按下按鈕2時獲取目標任務。
您在我的其他答案中的一條評論中提到了一個鏈接,看起來該鏈接描述了如何使其可取消。 我已經調整了我的例子來支持這個:
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爆發。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.