2010-02-10 77 views
14

我一直在閱讀.NET線程,並且正在研究一些使用ManualResetEvent的代碼。我在互聯網上找到了很多代碼示例。然而,閱讀文檔WaitHandle的時候,我看到以下內容:我是否需要在ManualResetEvent上調用Close()?

的WaitHandle實現的Dispose 模式。請參閱實施完成和 處置以清理非託管 資源。

無樣品似乎對他們所創造的ManualResetEvent的對象調用.Close(),即使是好的Recursion and Concurrency從pfxteam博客編輯文章 - 這有使用塊我已經錯過一)。這僅僅是例子的監督,還是不需要?我很好奇,因爲WaitHandle「封裝了特定於操作系統的對象」,所以很容易出現資源泄漏。

回答

11

一般來說,如果一個對象實現了IDisposable它是這樣做的原因,你應該叫Dispose(或Close,視情況而定)。在您的網站示例中,ManualResetEvent包裝在using語句中,該語句將「自動」處理呼叫Dispose。在這種情況下,CloseDispose同義(在提供Close方法的大多數IDisposable實現中都是如此)。

從示例代碼:

using (var mre = new ManualResetEvent(false)) 
{ 
    ... 
} 

擴展到

var mre = new ManualResetEvent(false); 
try 
{ 
    ... 
} 
finally 
{ 
    ((IDispoable)mre).Dispose(); 
} 
2

你會注意到代碼

using (var mre = new ManualResetEvent(false)) 
{ 
    // Process the left child asynchronously 
    ThreadPool.QueueUserWorkItem(delegate 
    { 
     Process(tree.Left, action); 
     mre.Set(); 
    }); 

    // Process current node and right child synchronously 
    action(tree.Data); 
    Process(tree.Right, action); 

    // Wait for the left child 
    mre.WaitOne(); 
} 

使用 '使用' 關鍵字。這會在完成時自動調用dispose方法,即使代碼拋出異常。

+0

查看該代碼時,我完全錯過了使用塊。感謝您指出。 – 2010-02-10 03:54:55

2

我用ManualResetEvent了很多,不認爲我曾經用一個單一method--內它總是一個類的實例字段。因此using()通常不適用。

如果你有一個類的實例字段是ManualResetEvent一個實例,讓你的類實現IDisposable並在Dispose()方法調用ManualResetEvent.Close()。然後在你的課程的所有用法中,你需要使用using()或使包含類實現IDisposable並重復,並重復...

2

如果你使用的是帶匿名方法的ManualResetEvent,那麼它顯然是有用的。但是,正如山姆所說,他們經常可以被傳播到工人身邊,然後安置並關閉。

所以我會說這取決於你如何使用它的上下文 - the MSDN WaitHandle.WaitAll()代碼示例有一個很好的例子,我的意思是。

這裏的基礎上如何與using語句創建WaitHandles會異常的MSDN樣本的例子:

System.ObjectDisposedException
「安全把手已關閉」

const int threads = 25; 

void ManualWaitHandle() 
{ 
    ManualResetEvent[] manualEvents = new ManualResetEvent[threads]; 

    for (int i = 0; i < threads; i++) 
    { 
     using (ManualResetEvent manualResetEvent = new ManualResetEvent(false)) 
     { 
      ThreadPool.QueueUserWorkItem(new WaitCallback(ManualWaitHandleThread), new FileState("filename", manualResetEvent)); 
      manualEvents[i] = manualResetEvent; 
     } 
    } 

    WaitHandle.WaitAll(manualEvents); 
} 

void ManualWaitHandleThread(object state) 
{ 
    FileState filestate = (FileState) state; 
    Thread.Sleep(100); 
    filestate.ManualEvent.Set(); 
} 

class FileState 
{ 
    public string Filename { get;set; } 
    public ManualResetEvent ManualEvent { get; set; } 

    public FileState(string fileName, ManualResetEvent manualEvent) 
    { 
     Filename = fileName; 
     ManualEvent = manualEvent; 
    } 
} 
+0

這似乎是一個示例,其中.Close()未在ManualResetEvent上調用,並且沒有使用塊。我不認爲工作人員可以關閉它,因爲主線程正在WaitHandle.WaitAll(manualEvents)調用中使用它。 – 2010-02-10 13:20:01

+0

@Kevin我的觀點是WaitHandles數組無法包含在使用子句中時創建爲*我認爲*他們會在他們到達時關閉,但我需要檢查。 – 2010-02-10 14:10:27

17

我最近被轉發摘錄自C# 4.0 in a Nutshell: The Definitive Reference By Joseph Albahari,Ben Albahar一世。在頁834,在第21章:線程有一節討論這一點。

處置等待句柄

一旦你有一個等待 句柄後,就可以調用它關閉方法 釋放操作系統 資源。或者,你可以簡單地 刪除所有引用到等待 手柄,讓垃圾回收 到以後的某個時候爲你做的工作 (等待句柄落實處置 模式,即終結呼籲 關閉)。這是爲數不多的 場景中對這個備份 依託是一個(可以說)可以接受的,因爲等待 手柄有一個光OS負擔 (異步委託依靠 正是這種機制來釋放 他們的IAsyncResult的等待句柄)。

當應用程序 域卸載時會自動釋放等待句柄 。

+0

WaitHandle.Finalize的文檔說,不再有.NET 2.0的實現。您也可以使用反編譯器來查看。 WaitHandle不再有終結器。我不知道爲什麼,但任何被拋棄的WaitHandle似乎都會泄漏它。請參閱http://msdn.microsoft.com/en-us/library/vstudio/bb291974(v=vs.90).aspx – Djof 2013-06-14 19:39:08

+4

@Djof:儘管'WaitHandle'不再有'Finalize'方法,我不'我認爲這意味着他們會泄漏。相反,清理是在'WaitHandle'持有引用的'SafeHandle'中處理的。 – supercat 2013-09-13 21:33:24

相關問題