.NET Framework 4.6 and 4.5 – walk-through – (Part 11)

When you pass an Action to Task.Run:

Task.Run(someAction);

that’s exactly equivalent to:

Task.Factory.StartNew(someAction,
CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

Task.Run provides eight overloads, to support all combinations of the following:

  1. Task vs Task<TResult>
  2. Cancelable vs non-cancelable
  3. Synchronous vs asynchronous delegate

Calling Unwrap on a Task<Task> gives you back a new Task (which we often refer to as a proxy) which represents the eventual completion of the inner task.  Similarly, calling Unwrap on a Task<Task<TResult>> gives you back a new Task<TResult> which represents the eventual completion of that inner task. (In both cases, if the outer task is Faulted or Canceled, there is no inner task, since there’s no result from a task that doesn’t run to completion, so the proxy task then represents the state of the outer task.)

var t = Task.Run(async delegate
{
await Task.Delay(1000);
return 42;
});

the type of ‘t’ is Task<int>, and the implementation of this overload of Task.Run is basically equivalent to:

var t = Task.Factory.StartNew(async delegate
{
await Task.Delay(1000);
return 42;
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();

 

int result = await Task.Factory.StartNew(async delegate
{
await Task.Delay(1000);
return 42;
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();

or, instead of using Unwrap, I could use a second await:

int result = await await Task.Factory.StartNew(async delegate
{
await Task.Delay(1000);
return 42;
}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

await await” here is not a typo. Task.Factory.StartNew is returning a Task<Task<int>>. Await’ing that Task<Task<int>> returns a Task<int>, and awaiting that Task<int> returns an int.

The ‘await’ keyword has nothing to do with invoking methods in this regard… nothing.  It doesn’t influence how a method is invoked, nor is it somehow associated by the compiler with a subsequent method call.

await keyword isn’t operating on the method or somehow influencing the method’s invocation.  Rather, it’s operating on the result of the method’s invocation.  The statement:

await FooAsync();

is functionally identical to:

var t = FooAsync();
await t;

just as:

return Foo();

is functionally identical to:

var t = Foo();
return t;

Interlocked.CompareExchange

Compares two 32-bit signed integers for equality and, if they are equal, replaces the first value.

public static int CompareExchange(
	ref int location1,
	int value,
	int comparand
)

If comparand and the value in location1 are equal, then value is stored in location1. Otherwise, no operation is performed. The compare and exchange operations are performed as an atomic operation. The return value of CompareExchange is the original value in location1, whether or not the exchange takes place.

 The following code example demonstrates a thread-safe method that accumulates a running total. The initial value of the running total is saved, and then the CompareExchange method is used to exchange the newly computed total with the old total. If the return value is not equal to the saved value of the running total, then another thread has updated the total in the meantime. In that case, the attempt to update the running total must be repeated.

In many scenarios, it is useful to enable a Task<TResult> to represent an external asynchronous operation. TaskCompletionSource<TResult> is provided for this purpose. It enables the creation of a task that can be handed out to consumers, and those consumers can use the members of the task as they would any other.

 

Nano Server

 

Leave a Reply

Your email address will not be published. Required fields are marked *