Skip to content

Async Package

kobi2294 edited this page Apr 22, 2019 · 6 revisions

The Async Package

Overview

This package provides extra features on top of those provided by TPL. It mainly focuses on 2 issues:

  1. Synchronizing access to shared resources (to compansate for the lack of lock and blocking in classic asynchronous work).
  2. Controlling which code runs on which thread. Specifically, provide means that will allow encapsulation of synchronization context (see details area to understand what this means 😄 )

The package content

The async package has 2 sub packages:

In Addition the package contains the following classes:

  • AsyncContextRunner - A wrapper around TaskSchduler that helps to run code using that specific scheduler. Allows to run both async methods and "normal" methods on the selected TaskSchduler
  • DeferredTask<T> - A fusion of Task.FromResult<T> and TaskCompletionSource<T>. Creates a task that has a result that is known in advanced, but this task is not created completed. You complete it by calling the method DeferredTask.Complete.
  • SingleThreadTaskScheduler - A task scheduler that has it's own thread. It creates a thread when it is constructed, and schdules all tasks to this thread.
  • The Tasks class - A static class with some TPL related shortcuts and extension methods

Encapsulation of synchronization context

MVVM development relies heavily on events and callbacks. A view model defines a set of events to notify the view of changes (such as PropertyChanged, CollectionChanged in collections, CanExecuteChanged in commands, ErrorsChanged in validation, and the list goes on). It also registers to events that model services expose in order to react to changes in data model. If you use the reactive pattern, you may not use events, but you will pass callbacks to observables.

When a ViewModel, or a service provides a delegate to another service (either by registering to events, or by providing callbacks any other way) there is a problem with encapsulation, since the code that decides on which thread to run the delegate belongs to the service. A more correct approach will be to allow each object to decide where to run it's code. So if Object A registers to an event on Object B, Object A should be the one to decide which thread will run the event handler. Which is not the default way in C#.

So, as said above, one of the 2 targets of the kit's async package, is to provide easy means to allow such seperation of concerns. Services should decide which threads their code should run in, and when they expose events, each object that registers to the event should be able to control the thread that runs the handler.