2010-12-03 57 views
2

考慮一下:Task.Factory.StartNew「行動」的說法,更高層次的局部變量

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

現在,我的問題:我可以使用dataRequest lambda表達式中,而不是將它作爲第二個參數來StartNew方法?我的擔心是 - 該方法將在不同的線程上執行,而且我不確定dataRequest在那裏使用時是否保持其狀態。

回答

5

是的,你可以。
這叫做Closure;這是一個非常強大的功能。

線程的安全性,或缺乏,將沒有什麼不同。
無論您是通過關閉還是通過StartNew參數獲取實例,它仍然是同一個對象。 (除非它是一個struct,這將是難以形容的邪惡)

+0

因此,它會保持dataRequest變量被垃圾收集,直到任務執行?我找不到這方面的任何信息... – Andrey 2010-12-03 03:19:50

+1

@Andrey:是的。如果你能看到一個對象,它不能被GC'd。你不需要擔心這一點。 (除了使用弱引用或不安全/非託管代碼) – SLaks 2010-12-03 03:20:49

+0

好的,謝謝!我只是不確定C#中的閉包工作是否與JavaScript不同 - 顯然他們是這樣做的。在JavaScript中,回調會在你使用它的時刻使用變量的當前狀態,這就是爲什麼你必須做「雙閉合」。我很高興C#更聰明:) – Andrey 2010-12-03 03:23:22

1

回答你的問題,你可以但它可能不會線程安全。我學會使用ThreadLocal來提供幫助。

你的委託方法應該隔離你的dataRequest。

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

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

    /// 
}, dataRequest); 

/*我把它從Pro .NET Parallel Programming in C# */

2

我有同樣的問題。使用Action而不是lambda表達式。

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()); 
}