2012-12-27 42 views
11

我有一個WebService創建一個任務和一個延續任務。延續任務在與前面相同的線程

在第一個任務中,我們設置Thread.CurrentPrincipal中

因此,當ContinuationTask啓動時,它不再具有Thread.CurrentPrincipal中。

我想在ContinuationTask指定它應該在同一個線程作爲它的先行詞運行。

我已經搜索了網頁,但是我只發現線程在SynchronizationContext中運行的要求,因此我開始認爲我缺少一些基本規則,特別是關於Thread.Principal應該如何工作。

+3

搭售任務複製到線程是一個壞主意,而且容易出錯的異常情況。嘗試將WindowsIDentity或標記對象作爲狀態傳遞給任務並在每個任務中模擬用戶,而不是修復線程的主體並要求所有任務使用同一個線程。否則,如果發生異常並且忘記清除標識 –

+0

PS,則可能會冒更改ThreadPool身份的風險。你使用什麼類型的身份? WindowsIdentity還是別的? –

+1

我們實現了我們自己的IPrincipal,它是進行身份驗證的應用程序本身。 看起來最好的是通過IPrincipal之間的任務。 –

回答

14

首先,不要使用TaskContinuationOptions.ExecuteSynchronously爲了這個目的!你不能在同一個線程上強制繼續。它只能以很高的概率工作。總有些情況下它不起作用:太多的遞歸會導致TPL不能同步執行。自定義TaskScheduler也沒有義務支持這一點。

這是一種常見的誤解,尤其是因爲它在網上被錯誤地傳播。下面是有關該主題的一些閱讀:http://blogs.msdn.com/b/pfxteam/archive/2012/02/07/10265067.aspx

如果您需要在同一線程上運行,這樣做:

Task.Factory.StartNew(() => { First(); Second(); }); 

那麼容易。

讓我說明爲什麼這樣的作品通過展示一種替代方案:

void MyCompositeTask() 
{ 
    var result = First(); 
    Second(result); 
} 
Task.Factory.StartNew(() => MyCompositeTask()); 

這看起來更直觀:我們通過MyCompositeTask到TPL運行。 TPL不關心我們在回調中做什麼。我們可以做我們想做的任何事情,包括調用多種方法並傳遞結果。

+1

沒有冒犯,但我會採取本書的作者(許多人考慮成爲C#4.0的權威參考)是比您更可靠的資源。請提供一些參考資料或閱讀材料,說明您提供的解決方案如何確保以滿足OP所尋找行爲的方式調用這兩種方法。 –

+0

我並不傲慢,不承認這是一個更合適的解決方案,但是當你告訴我一本關於這個主題的着名書籍的作者是「錯誤的」時,我希望看到更多的證據。 99.999999%已經足夠被認爲是100.在這種情況下,你談論的差異似乎並不值得考慮,尤其是當深遞歸在這裏沒有影響時 –

+2

@JesseCarter你不覺得執行另一種方法會保證委託人持續存在? *一切*在普通的方法調用之間依然存在。深度遞歸發生在潛在的無限延續鏈上。以下是ExecSync未生效的多種情況:http://blogs.msdn.com/b/pfxteam/archive/2012/02/07/10265067.aspx(可信來源)。 「 – usr

4

從我的C#教材(C#4.0中果殼):

你可以迫使他們[續任務]通過調用ContinueWith時指定TaskContinuationOptions.ExecuteSynchronously同一線程[他們的前因]上執行:可以在減少間接性的情況下提高非常精細的延續性能。

原則上我沒有嘗試過,但它似乎是你正在尋找的,可以與Thread.CurrentPrincipal一起使用。

這裏是一個鏈接到MSDN article一些更具體的例子還有

+1

你不能強迫它。它只能以很高的概率工作!有*總是*它不起作用的情況。因此被投票。 – usr

+1

下面是我以前的聲明的參考:http://blogs.msdn.com/b/pfxteam/archive/2012/02/07/10265067.aspx – usr

3

設置池線程的身份不是一個好主意。如果您忘記在異常處理程序中清除標識,它會將您與此特定的線程綁定在一起,並在發生異常時冒着「泄漏」身份的風險。您最終可能會使用「泄露」身份運行不相關的任務。

嘗試將WindowsIdentity對象傳遞給任務並使用WindowsIdentity.Impersonate冒充。這將允許您使用任何可用的線程,並且即使發生異常也會安全地清除身份。

你可以嘗試這樣的事情:

WindowsPrincipal myPrincipal=...; 
... 
var identity=(WindowsIdentity)myPrincipal.Identity; 
var task=Task.Factory.StartNew(ident=>{ 
     var id=(WindowsIdentity)ident; 
     using(var context=id.Impersonate()) 
     { 
      //Work using the impersonated identity here 
     } 
     return id; 
    },identity). 
.ContinueWith(r=>{ 
     var id = r.Result; 
     using(var context=id.Impersonate()) 
     { 
      //Work using the impersonated identity here 
     } 
}); 

using語句確保即使發生異常模擬的標識被清除。

2

呼叫與TaskScheduler.FromCurrentSynchronizationContext(延續):

Task UITask= task.ContinueWith(() => 
{ 
this.TextBlock1.Text = "Complete"; 
}, TaskScheduler.FromCurrentSynchronizationContext()); 

https://stackoverflow.com/a/4331287/503969

+0

」InvalidOperationException未處理:當前的SynchronizationContext不能用作TaskScheduler。「 :-( – Ricibob

+1

http://stackoverflow.com/a/8246053/503969 - 保存你谷歌搜索:) –