10

I have seen that in .NET 4.5 that Task.Run() is the equivalent to

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

But in .NET 4.0, TaskCreationOptions.DenyChildAttach does not exist. Is this where TaskEx.Run comes in? A comment in this question seems to indicate that, but no elaboration is given. What is the equivalent in .NET 4.0 for .NET 4.5's Task.Run?

Community
  • 1
  • 1
Mike_G
  • 16,237
  • 14
  • 70
  • 101
  • I'm not seeing that 4.5 `Factory.StartNew` uses `DenyChildAttach` (see http://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/TaskFactory.cs) The default `TaskFactory` used with `Task.Factory` is created with default `TaskCreationOptions.None` (http://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/TaskFactory.cs) Where did you read about this? – Peter Ritchie Sep 24 '14 at 15:00
  • MSDN states that Task.Run in .NET 4.5 is the equivalent of using DenyChildAttach: http://msdn.microsoft.com/en-us/library/hh195051.aspx aslo http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx – Mike_G Sep 24 '14 at 15:02
  • Sorry, I read that backwards. for some reason I read that `Task.Factory.StartNew` defaulted to `DenyChildAttach`. Yes, `Task.Run()` defaults to this as opposed to `Task.Factory.StartNew(Action)`. There is no `TaskEx` class in release bits. The equivalent in 4.0 is to *not* use `TaskCreationOptions.AttachedToParent`. A task is not a child without `AttachedToParent` – Peter Ritchie Sep 24 '14 at 15:19
  • That's strange because I installed the MS BCL Portability Pack using VS 2013 NuGet manager and TaskEx is in there. – Mike_G Sep 24 '14 at 15:23
  • 1
    Ahh, Microsoft.Bcl.Async (I assume you mean that instead of the targeting pack because it replaced the targeting pack). That's not "release bits" or part of TPL. Microsoft.Bcl.Async extends .NET 4.0 and .NET 4.0 doesn't have the `Task.Run` convenience statics and they can't *replace* the existing `Task` class--so `TaskEx` is included in Microsoft.Bcl.Async. Other than the default `TaskCreationOptions.DenyChildAttach`, they work the same as the `Task.Run` equivalents. I.e. `TaskEx.Run` is there because .NET 4.0 `Task.Run` doesn't exist (which are more convenient than `TaskFactory.StartNew`) – Peter Ritchie Sep 24 '14 at 15:49
  • 1
    You'll notice that there are the same `TaskEx.Run` overloads as `Task.Run` overloads. – Peter Ritchie Sep 24 '14 at 15:52

1 Answers1

11

The DenyChildAttach option not only doesn't exist in the TaskCreationOptions enum, it doesn't exist in the framework itself. The code that would actually deny the attempted attachment of a child task doesn't exist in .Net 4.0. (more in New TaskCreationOptions and TaskContinuationOptions in .NET 4.5).

So the exact equivalent of Task.Run doesn't and can't exist in .Net 4.0. The closest thing to it would be to simply not use the AttachedToParent value in that enum:

public static Task<TResult> Run<TResult>(Func<TResult> function)
{
    return Task.Factory.StartNew(
        function, 
        CancellationToken.None, 
        TaskCreationOptions.None, 
        TaskScheduler.Default);
}

A more important difference IMO is the support for async delegates in Task.Run. If you pass an async delegate (i.e. Func<Task<TResult>>) to Factory.StartNew you get back in return Task<Task<TResult>> instead of Task<TResult> as some would expect which is a source of many headaches. The solution to that is to use the TaskExtensions.Unwrap extension method that "Creates a proxy Task that represents the asynchronous operation of a Task<Task<T>>":

public static Task<TResult> Run<TResult>(Func<Task<TResult>> function)
{
    return Task.Factory.StartNew(
        function, 
        CancellationToken.None, 
        TaskCreationOptions.None, 
        TaskScheduler.Default).Unwrap();
}
bimjhi
  • 311
  • 2
  • 11
i3arnon
  • 113,022
  • 33
  • 324
  • 344