2012-03-16 165 views
2

我有一個在線程中使用非託管資源的類,它也可以在不使用時進入休眠狀態。我正在實施處理它,請參閱下面的示例代碼(注意它是我的應用程序的一個愚蠢的版本)。我加了(TheThread.IsAlive());在執行DestroySomeUnmangedResouces()之前,可以將其設置爲true。我不認爲我所做的是正確的,所以如果有人能夠提出更好的模型,我會很感激。以線程處理非託管資源

protected virtual void Dispose(bool disposing) 
{ 
    if (!disposed) 
    { 
     if (disposing) 
     { 
      //managed 
     } 

     //unmanged 
     _stopTheThread = true; 
     startTheThreadEvent.Set(); 
     while(TheThread.IsAlive()); 
    } 
    disposed = true; 
} 

private void TheThread() 
{ 
    while (!_stopTheThread) 
    { 
     if (state == State.Stopped) 
     { 
      // wait till a start occurs 
      startTheThreadEvent.WaitOne(); 
     } 
     switch (state) 
     { 
      case Init: 
       CreateSomeUnmangedResouces(); 
       break; 

      case Run:  
       DoStuffWithUnmangedResouces(); 
       break; 

      case Stop: 
       DestroySomeUnmangedResouces(); 
       break; 
     } // switch 
    } 
    // Release unmanaged resources when component is disposed 
    DestroySomeUnmangedResouces(); 
} 
+0

如果你的主類也有一個Finalizer,這是GC上的謀殺。 – 2012-03-16 15:24:34

+0

這是指使用「while(TheThread.IsAlive());」或者是其他東西? – integra753 2012-03-16 15:28:48

+0

請不要用「C#:」等來標題。這就是標籤的用途。 – 2012-03-16 16:04:48

回答

2

您似乎想等到您的工作線程退出。爲此,你可以簡單地使用Thread.Join(),它將阻塞,直到你的線程退出。

目前,您正等待100%的CPU在您的等待線程上,因爲如果工作線程仍然存在,您會進行輪詢。資源密集程度較低的變體是受限制的輪詢,您至少在時間片(15毫秒)之間睡眠。

但是最好的方法是等待一個同步原語獲取信號並在condtion變爲true時喚醒你的線程。 Thead.Join因此是要走的路。

+0

我看到你在說什麼,但是在dispose方法中調用任何阻塞方法是一個好習慣嗎?即g說DoStuffWithUnmangedResouces()花了5分鐘才完成。 – integra753 2012-03-16 15:23:03

+0

您可以使用超時的Thread.Join。但如果您想等待或不等待,則由您決定。無論選擇哪條路線,您都必須忍受後果(如果您嘗試再次打開資源,關機時間過長甚至關機時出現死鎖,仍會鎖定資源)。什麼更好取決於你的資源以及你如何訪問它們以及你想要提供什麼運行時不變量。 – 2012-03-16 20:48:46

1
private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false); 
    private readonly ManualResetEvent _threadStoppedEvent = new ManualResetEvent(false); 
    private bool disposed; 
    private int checkInterval = 10;//ms 


    protected virtual void Dispose(bool disposing) 
    { 
     if (!disposed) 
     { 
      if (disposing) 
      { 
       //managed 
      } 

      //unmanged 
      _stopEvent.Set(); 
      _threadStoppedEvent.WaitOne(); 
     } 
     disposed = true; 
    } 

    private void TheThread() 
    { 
     CreateSomeUnmangedResouces(); 

     while (!_stopEvent.WaitOne(checkInterval)) 
     { 
      DoStuffWithUnmangedResouces(); 
     } 

     DestroySomeUnmangedResouces(); 

     _threadStoppedEvent.Set(); 
    } 

或者你可以用它代替_threadStoppedEvent的Thread.join(),如果你的線程沒有背景

1

呼叫者呼叫處理應該掃蕩的話題 - 最好的辦法是調用它作爲加入阿洛伊斯建議。一旦線程加入後,你就可以銷燬現在發生在調用者線程上的非託管資源。例如:

protected virtual void 
    Dispose 
     (bool disposing) 
    { 
     if (!disposed) 
     { 
      if (disposing) 
      { 
       if(TheThread != null) 
       { 
        // send a signal to stop the thread. 
        _stopTheThread = true; 
        startTheThreadEvent.Set(); 

        // Join the thread - we could timeout here but it should be the 
        // responsibility of the thread owner to ensure it exits 
        // If this is hanging then the owning object hasn't terminated 
        // its thread 
        TheThread.Join(); 

        TheThread = null; 
       } 
      } 

      // Now deal with unmanaged resources! 
      DestroySomeUnmangedResouces(); 
     } 

     disposed = true; 
    } 

這種方法的一個缺點是我們假設線程最終會退出。它可能掛起,這意味着停止線程的信號是不夠的。 Join有overloads,其中包含超時,可用於防止掛起調用線程(請參閱上面代碼示例中的註釋)。

+0

我想那麼我應該使用TheThread.Join(Int32)。如果失敗了,拋出異常似乎是明智的(因爲它是一種特殊情況)? – integra753 2012-03-16 16:31:10

+0

是的,你可以。如果線程在millisecondsTimeout參數指定的時間量過去之後尚未終止,則Join(Int32)將返回false。 – Jeb 2012-03-16 16:32:42

+0

我正在使用上面的方法,但使用TheThread.Join()看到奇怪的結果。當我調用TheThread.Join()時,它會阻塞主線程和TheThread。我可以這樣說,因爲在Join()的調用之後沒有從TheThread輸出調試代碼。如果我在TheThread.Join()上指定了一個超時,它將返回失敗,之後我可以看到TheThread解鎖。我不知道是什麼使這發生? – integra753 2012-03-20 11:33:43

0

如果正在運行的線程持有對對象的直接或間接強引用,則此引用將阻止該對象變爲符合垃圾回收的條件。因此沒有任何理由在這樣的對象上有終結器。

然而,如果該線程將只作爲參考一些其他特定對象比其他東西舉行的線程,它可能是有益的線程持有WeakReference到對其他對象是相關的長,並在其他對象超出範圍時關閉。這種關閉可以通過讓線程定期檢查WeakReferenceIsAlive屬性來完成,或者通過讓另一個對象包含一個終結器來完成,該終結器將指示線程關閉。雖然定期輪詢這樣的事情在某種意義上是惡意的,並且使用終結器可能會加快線程的關閉,但我認爲輪詢可能仍然更好。雖然終結器可能會通知線程應該執行某些操作,並且有時候這樣做可能是合適的,但總體而言,最終確定了一個對象意味着沒有人過度關心即時清理。在線程關閉之前再增加幾秒鐘的延遲可能不會傷害任何東西。