The first sample is: there has two actions that we want to run in background sequentially. When the primary action was done, it would updates the UI likes changes text content or enables button. And then the secondary action was done, it needs to refresh UI again.
Maybe there were many solutions to design implementation code using thread invoke or whatever others in past, but in .NET 4.0 or later version, it could be programmed more easily and clearly, following is the sample.
public MainWindow() { InitializeComponent(); var backgroundScheduler = TaskScheduler.Default; var currentScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task.Factory.StartNew (delegate { PrimaryAction(); }, backgroundScheduler).ContinueWith (delegate { UpdateUI(); }, currentScheduler).ContinueWith (delegate { SecondaryAction(); }, backgroundScheduler).ContinueWith (delegate { RefresUIAgain(); }, currentScheduler); } private void PrimaryAction() { //do something in background } private void UpdateUI() { //update ui controls } private void SecondaryAction() { //another action to do in background } private void RefresUIAgain() { //update ui controls again }
The TaskScheduler provides different context for running thread that can helps us scheduling sequential tasks with Task.ContinueWith method.
The second sample is description of task's status in cases of action. It made confused me for a long time because I did not clarify the "cancel"'s meaning. There are some unit test methods to scribe it.
[TestMethod]
public void TaskRespondsCompletionWhenTokenRequestsCancellation()
{
CancellationTokenSource cts = new CancellationTokenSource();
var token = cts.Token;
Task task = new Task(()=>
{
while (!token.IsCancellationRequested)
{ /* do something repeatedly */ }
}, token);
task.Start();
while (task.Status != TaskStatus.Running)
{ /* util task is ready and running */ }
cts.Cancel(); //token requested cancellation
task.Wait(); //task wait for while loop
Assert.IsFalse(task.Status == TaskStatus.Canceled);
Assert.IsTrue(task.Status == TaskStatus.RanToCompletion);
}
Although the token is requested cancellation, but it means completion for the running task. The situation of task's status will be signed "Canceled" is requesting cancellation before task running.
[TestMethod]
public void TaskRespondsCanceledWhenTokenRequestsCancellation()
{
CancellationTokenSource cts = new CancellationTokenSource();
var token = cts.Token;
Task task = new Task(()=>
{
while (!token.IsCancellationRequested)
{ /* do something repeatedly */ }
}, token);
task.Start();
if (task.Status != TaskStatus.Running)
{
cts.Cancel(); //requests cancellation before task running
bool taskWaitThrowException = false;
try { task.Wait(); }
catch (Exception ex)
{
Assert.IsInstanceOfType(ex, typeof(AggregateException));
Assert.IsInstanceOfType(ex.InnerException, typeof(TaskCanceledException));
taskWaitThrowException = true;
}
Assert.IsTrue(task.Status == TaskStatus.Canceled);
Assert.IsTrue(taskWaitThrowException);
}
else
{
Assert.Inconclusive("Task was running before requesting cancellation");
try { cts.Cancel(); /* Clean up then manually re-test again */ }
catch { }
}
}
So we can using this behavior for purpose that there are two difference actions when a main task was canceled before its running or after.
But it seems not so much useful when I write down this article...
沒有留言:
張貼留言