3

Consider this:

void StartUpdate(DataRequest dataRequest)
{
    Task.Factory.StartNew(request => {... do something with "request" ...}, 
        dataRequest);
}

Now, my question: can I use dataRequest inside the lambda expression, instead of passing it as second parameter to StartNew method? My concern is - that method will be executed on a different thread and I'm not sure if dataRequest would keep its state when used there.

Andrey
  • 20,487
  • 26
  • 108
  • 176

3 Answers3

6

Yes, you can.
This is called a Closure; it's a very powerful feature.

The thread-safety, or lack thereof, will be no different.
Whether you get the instance through the closure or through a StartNew parameter, it's still the same object. (Unless it's a struct, which would be indescribably evil)

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • So it will keep dataRequest variable from being garbage collected until the task executes? I couldn't find any information on that... – Andrey Dec 03 '10 at 03:19
  • 1
    @Andrey: Yes. If you can see an object, it cannot have been GC'd. You _never_ need to worry about that. (Except when using weak references or unsafe / unmanaged code) – SLaks Dec 03 '10 at 03:20
  • Ok thanks! I just wasn't sure if closures in C# work differently from javascript - apparently they do. In javascript the callback would use current state of variable at the moment you are using it, and that's why there you have to do "double closure". I'm glad C# is smarter :) – Andrey Dec 03 '10 at 03:23
  • Bummer, it makes me wait 5 minutes before accepting this as an answer. I'll do it tomorrow :) Thanks again! – Andrey Dec 03 '10 at 03:24
  • And no, no passing structs as arguments :) – Andrey Dec 03 '10 at 03:25
  • What if dataRequest was a field defined in this class instead of an argument of this method? I know it's visible, but would its state persist afterward if it was modified inside the closure? – kappasims Mar 23 '12 at 15:26
2

I had the same problem. Use Action instead of the lambda expression.

private void StartUpdate(DataRequest dataRequest)
{
    Action<DataRequest> pobjAction = new Action<DataRequest>(DoSomething);
    Task.Factory.StartNew(pobjAccion, dataRequest);
}


private void DoSomething(DataRequest dataRequest)
{
    Trace.WriteLine(dataRequest.ToString());
}
Yuu
  • 29
  • 2
  • 2
    Unfortunately that doesn't work. TPL doesn't have generics with the Action<>, but it's working only on Action :) – Timotei Jan 22 '12 at 19:35
  • The solution would be to make the parameter on DoSomething of type Object or use a Func with a param inside as a StartNew argument. – Blake Niemyjski May 02 '12 at 14:53
1

Answer to your question, You can but it may not threadsafe. I learn to use ThreadLocal to help.

inside your delegate method should Isolate your dataRequest.

ThreadLocal<DataRequest> tls = new ThreadLocal<DataRequest>();

Task.Factory.StartNew(request => {
   tls.Value = (DataRequest)stateObject;

   ///
}, dataRequest);

/* I get it from Pro .NET Parallel Programming in C# */

Jirapong
  • 24,074
  • 10
  • 54
  • 72
  • This won't help at all. It's still the same instance. – SLaks Dec 03 '10 at 03:39
  • this doesn't answer my question. I was not concerned about thread safety - this object I pass will not be accessed by anybody else, I was only concerned about accessibility of the object inside that task execution thread, and SLaks answered my question. – Andrey Dec 03 '10 at 04:57
  • sorry, i missed your point on this. - likely to delete my answer but let's keep it to show my mistake :-) Cheers. – Jirapong Dec 07 '10 at 02:07