2014年8月24日 星期日

About the SynchronizationContext with UI threading, and WCF with STA threading

There has a new WPF project of my job is using multiple UI threads interact with each other and background thread. When I got a while of research and finally found a good introduction about the SynchronizationContext from CodeProject.

Understanding SynchronizationContext Part I, Part II and Part III.

These articles are very simple and easy to understand that I don't need any additional example code to scribe it.

2014年7月30日 星期三

Scheduler, Task and Cancellation in dot NET programming

There has many opportunities using Task (or Thread) to program our UI related applications. About the basic usage of Task, the MSDN has many sample code and some coding forum also has lots of discussion. So, this article will mainly point some kinds of situation using task methods between fluent UI with heavy loading work, but not how to use Task class.

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...