2012-03-16 14 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

メインクラスにもファイナライザがある場合、これはGCでの殺人です。 –

+0

これは、 "while(TheThread.IsAlive());"または、他の何か? – integra753

+0

タイトルに「C#:」などのプレフィックスを付けないでください。それはタグのためのものです。 –

答えて

2

ワーカースレッドが終了するまで待つことをお勧めします。このために、あなたのスレッドが終了するまでブロックするThread.Join()を使うことができます。

現在、ワーカースレッドがまだ生きている場合にポーリングを行うため、待機中のスレッドで100%CPUを食べています。リソースの消費量の少ない方法は、少なくともタイムスライス(15ms)の間にスリープ状態にあるスロットルポーリングです。

しかし、最も良い方法は、条件が成立したときに信号を受け取ってスレッドを起動させる同期プリミティブを待つことです。そうです。ジョインは行く道です。

+0

私はあなたが言っていることを見ていますが、disposeメソッドでブロッキングメソッドを呼び出すのは良い方法ですか? e。g DoStuffWithUnmangedResouces()が完了するまでに5分かかりました。 – integra753

+0

Thread.Joinをタイムアウトで使用できます。しかし、あなたが待っているかどうかはあなた次第です。どんなルートを選んでも、結果を生かさなければなりません(リソースを再度開こうとするとロックされたリソース、非常に長いシャットダウン時間、シャットダウン中のデッドロック)。あなたのリソースとそれらにアクセスする方法と、あなたが提供したいランタイムインバリアントがどのように優れているかによって異なります。 –

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

それとも、Thread.Joinを(使用することができます)の代わりに_threadStoppedEventのあなたのスレッドは、バックグラウンド

1

でない場合にdisposeを呼び出す呼び出し側は、スレッドを一掃すべきである - 最良の方法は、としてそれに参加呼び出すことですアロイスは提案している。スレッドが参加すると、アンマネージリソースを破棄して、呼び出し元スレッドで発生するようにできます。例えば、このアプローチの1つの欠点は、スレッドが最終的に終了すると仮定していることである。 がハングする可能性があります。つまり、スレッドを停止する信号が十分でないことを意味します。 Joinにはoverloadsがあり、タイムアウトが含まれています。このタイムアウトは、呼び出し元スレッドのハングアップを防ぐために使用できます(上記のコードサンプルのコメントを参照)。

+0

私はTheThread.Join(Int32)を使うべきだと思います。これが失敗した場合、例外をスローすることは理にかなっているようです(例外的な状況として)。 – integra753

+0

はい、できます。 millisecondsTimeoutパラメータで指定された時間が経過した後にスレッドが終了しなかった場合、Join(Int32)はfalseを返します。 – Jeb

+0

私は上記の方法を使用していますが、私はTheThread.Join()で奇妙な結果を見ています。 TheThread.Join()を呼び出すと、メインスレッドとTheThreadがブロックされます。私は、デバッグコードがTheThreadからJoin()への呼び出しに従って出力されないので、これを知ることができます。 TheThread.Join()でタイムアウトを指定すると失敗し、この後はTheThreadのブロックを解除することができます。私は何が起こっているか分かりません。 – integra753

0

実行中のスレッドがオブジェクトへの直接的または間接的な強力な参照を保持している場合、このような参照はオブジェクトがガベージコレクションの対象にならないようにします。したがって、実際にそのようなオブジェクトにファイナライザを持つ理由はありません。

いくつかの他の特定の目的は、スレッドが他のオブジェクトにWeakReferenceを保持するためのスレッドは、それが有用であり得る以外に保持されている基準として、しかし、スレッドだけ長いなどの関連する場合、その他のオブジェクトが範囲外になると自動的にシャットダウンします。このシャットダウンは、スレッドがIsAliveプロパティー(WeakReference)を定期的にチェックするか、または他のオブジェクトにスレッドをシャットダウンするように通知するファイナライザを含めることによって実行できます。そのようなものの定期的なポーリングはある意味では厄介なものですが、ファイナライザを使用するとスレッドのシャットダウンがやや早くなる可能性があります。ファイナライザがスレッドに何かをすべきことを通知することは可能ですが、そうすることが適切な場合がありますが、一般にオブジェクトがファイナライズされたということは、誰も迅速なクリーンアップを心配していませんでした。スレッドがシャットダウンする前に別の数秒の遅延を追加することは、おそらく何も傷つけることはありません。

関連する問題