Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing parameter into a Task.Factory.StartNew

Given the following code:

string injectedString = "Read string out of HttpContext";
Task.Factory.StartNew(() =>
 {
    MyClass myClass = new MyClass();
    myClass.Method(injectedString);
 }

Is this the best way to pass the string into the Task/Thread?

My concerns with this method are:

  • Would the garbage collector know when the string became out of context and clean it up correctly?
  • Is there a better way to inject dependencies into a Task breaking the link to the object in the main thread?

This is in a Asp.Net webservice, if it matters and is a fire and forget type thread, I'm not waiting for any kind of response.

My string is actually going to get read out of the HttpContext, which is one reason why I'm injecting it in this way (Thread does not have access to the calling threads HtppContext)

like image 222
Liam Avatar asked Nov 18 '13 11:11

Liam


People also ask

What does Task factory StartNew do?

StartNew(Action<Object>, Object, CancellationToken, TaskCreationOptions, TaskScheduler) Creates and starts a task for the specified action delegate, state, cancellation token, creation options and task scheduler.

What is the difference between task run and task factory StartNew?

Task. Run(action) internally uses the default TaskScheduler , which means it always offloads a task to the thread pool. StartNew(action) , on the other hand, uses the scheduler of the current thread which may not use thread pool at all!


2 Answers

You should probably use the Task.Factory.StartNew(Action<object> action, object state) overload to pass state into your new task.

Task.Factory.StartNew((object myState) => {
    var i = (int)myState;

    //Do calculations...
    var x = i + 10; 
}, 10);
like image 59
tucaz Avatar answered Sep 18 '22 10:09

tucaz


Your lambda will be hoisted out into a compiler generated class. The injectedString variable will become a field of that class.

So, it will be garbage collected when the generated class is out of scope (which is basically at the very end of your lambda), and the GC decides to perform a collection.

In response to your comment:

There is no duplication. The compiler turns this:

 string injectedString = "Read string out of HttpContext";
 Task.Factory.StartNew(() =>
 {
    MyClass myClass = new MyClass();
    myClass.Method(injectedString);
 }

Into this:

CompilerGeneratedClass c1 = new CompilerGeneratedClass();
c1.injectedString = "Read string out of HttpContext";
// call delegate here.

Remember also: Strings are interned in the CLR. Even if the code was duplicated.. string literals will be interned in a pool. You would essentially only have a native WORD sized reference duplicated that pointed at the string (string literals only..)

like image 23
Simon Whitehead Avatar answered Sep 20 '22 10:09

Simon Whitehead