2013-12-12 128 views
0

我有一個訂閱事件的線程池線程,並且事件處理程序在另一個線程上被觸發。我的問題是,線程池線程什麼時候會返回到池中,或者只要事件訂閱處於活動狀態,它就會一直存在?線程池線程和偵聽事件

對於前:

public class RunTasks 
    { 
     private readonly MyTask _myTask; 

     public RunTasks(MyTask myTask) 
     { 
      _myTask = myTask; 
     } 

     public void Execute() 
     { 
      ThreadPool.QueueUserWorkItem((ignore) => _myTask.Execute()); 
     } 
    } 

    public class MyTask 
    { 
     private readonly IThridPartyApi _dependency; 

     public MyTask(IThridPartyApi dependency) 
     { 
      _dependency = dependency; 
     } 

     public void Execute() 
     { 
      _dependency.UpdateEvent -= Handler; 
      _dependency.UpdateEvent += Handler; 
     } 

     private void Handler(object sender, EventArgs e) 
     { 
      //raised on another thread as it's coming from a thrid party library. 
     } 
    } 

    public interface IThridPartyApi 
    { 
     event EventHandler<EventArgs> UpdateEvent; 
    } 

在上面的例子讓我們說RunTasks.Execute方法被調用多次(100系列)和事件處理程序,都會激發他們的50和推遲下一個50 - 將有多少活動線程正在偵聽事件訂閱?我在我的應用程序中有這個場景,所以試圖確保我沒有從這個實現中創建一個怪物。請你能幫我解答一個問題和一個理由嗎?如果這不是一個有效的實現,我該如何修改它(不使用異步,因爲我們仍然不在那裏)?請注意,Execute方法從UI按鈕處理程序中被觸發。

感謝, -Mike

+0

你爲什麼要實現自己的任務而不是使用TPL?它以一種更簡單的方式解決了這些問題。此外,如果你希望事件處理程序異步觸發(即使用'async'),你仍然需要使用TPL任務。 –

+0

我不使用異步,因爲我們仍然不在那裏。然而,我可以使用TPL,但是這怎麼解決呢? – Mike

+1

代碼現在的方式,一個ThreadPool線程只是設置一個處理程序併發布。處理程序由thir-party的線程執行。那是你想要的嗎? –

回答

0

代碼看起來現在的方式,一個線程池線程只是用來重置事件處理程序,那麼它釋放回池。事件處理程序將在引發UpdateEvent事件的任何人的線程中運行,即第三方API的線程。

要避免這種情況,您可以使用TaskCompletionSource將事件轉換爲任務。這在TPL and Traditional .NET Framework Asynchronous ProgrammingExposing Complex EAP operations as Tasks部分中有描述。這樣,事件處理程序將在ThreadPool線程中異步運行,並且第三方的線程不會被阻塞等待它。

在你的情況,你可以創建一個功能類似下面的返回retur任務:

public static Task<object> OnUpdateAsync(this IThridPartyApi dependency) 
{ 
    var tcs=new TaskCompletionSource<object>(); 
    EventHandler handler=null; 
    handler=(obj,args)=> 
    { 
     dependency.UpdateEvent-=handler; 
     //extract the response here 
     tcs.SetResult(response); 
    } 
    dependency.UpdateEvent+=handler; 
    return tcs.Task; 
} 

您可以將返回類型從object改變,無論你期望從第三方API接收。