2009-06-09 13 views
1

wpfアプリケーションでシングルトンパターンを使用していますが、複数のスレッドで動作させる方法に疑問があります。C#2つの異なるスレッドからシングルトンを操作する

私はMonitorと呼ばれるクラスを持っています。このクラスは、「デバイス」ごとに監視する「設定」のリストを保持しています。以下に概要を示します。私は、ユーザーの入力に応じて、 Monitor.getMonitor.register(ウォッチリスト)またはMonitor.getMonitor.unregister(...を)やっていると私は モニターを行うごとに200ミリ秒を実行しているDispatchTimerを持っている私のメインスレッドで

。 getMonitor.update()

public class Monitor 
{ 
    private Hashtable Master; //key=device, value=list of settings to watch 
    private static Monitor instance = new Monitor(); 
    private Monitor() {} 
    public static Monitor getMonitor() 
    { 
     return instance; 
    } 
    public void register(watchlist){...} 
    public void unregister(...){...} 
    public void update(){...} 

} 

register()/ unregister()hastableにadd/removeを実行します。 update()はハッシュテーブルからの読み込みのみを行います。

デバイスと設定の数に応じて、update()は、最新の値を取得して、ハステーブルとその内容を繰り返し処理します。 メインスレッドはregisterとregisterを頻繁に呼び出すかもしれません。私はGUIが応答性を保つことを望みます。これを行うには良い方法はありますか?

ハッシュテーブルをロック/ロック解除したりロックしたりするだけです。ハッシュテーブルに入る可能性のある奇妙な状態を捕まえるためにtry catch(alaは正常に失敗します)これを行うよりよい方法がいくつかあります(もしもアップデートが失敗しても何の問題も起こらないでしょう)。

何が起こっているのか分かりませんが、コード自体が実際に問題を示しているように見えます。任意の提案をありがとう...

答えて

11

私自身article on singleton implementationsを参照して、シングルトン自体がスレッドセーフをフェッチするようにしてください。

はい、またはをハッシュテーブルで繰り返すときにロックする必要があります。一度に複数のリーダーを使用できるようにするには、ReaderWriterLock(または.NET 3.5ではReaderWriterLockSlim)を使用することができます。反復処理中にたくさんの作業を行う必要がある場合は、コピーが少し古いと気にならない限り、常にロックしてコピーを取ったり、ロックを解除してから作業したりできます。

(.NET 2.0以降を使用している場合はHashtableの代わりにDictionary<TKey, TValue>のような汎用コレクションを使用することをお勧めします).NETの規約に沿ってメソッドの名前を変更することをお勧めします。現時点では明確なJavaのアクセント;)

+0

ReaderWriterLockSlimの良い言及。それはまだ見たことがありませんでした。 – Joe

+0

すごく早かった。応答していただきありがとうございます。これをちょっと試して理解してみてください。イタリック体でそれを詳しく教えてください。 私は3.5を使用しています。そして、.NETのコンベンションのリマインダーに感謝します。これは、1人のプロジェクトのようなものです。 – Sharun

+0

@Jon Singletonsに関する素晴らしい記事。私はJavaのダブルチェックロックの問題を認識していましたが、ネストされたクラスのシングルトンを作成することに気づいていませんでした。 CLR via C#は、私が同じことを成し遂げていると思うもっと簡単なテクニックを持っています。 – RichardOD

0

はい、あなたはそれぞれの操作をロックする必要があります。

public class Monitor 
{ 
    private Hashtable Master; //key=device, value=list of settings to watch 
    ... 
    private object tableLock = new object(); 
    public void register(watchlist) 
    { 
     lock(tableLock) { 
      // do stuff 
     } 
    } 
} 

あなたは、try/catchブロックを使用することを検討してはならない - 例外は、「正常」と考えるべきではありません状況が発生し、例外なくオブジェクトの状態が破損する可能性があります。

+0

クイック返信ありがとう! – Sharun

0

いくつの行がありますか? update()ループで繰り返しを行うのに時間がかかる場合を除き、私はおそらくロックします。主スレッドが潜在的に多数の登録/登録解除呼び出しを行っている場合、更新が繰り返し失敗する可能性があります.20または30回の連続呼び出しで失敗した場合は問題ですか?

そのコードはわかりました。私はおそらくクラスを封印させるだろう。私はまた、型付きの辞書対ハッシュテーブルを使用します。

+0

更新時間は一般的にはそれほど多くはありませんが、ネットワーク要求が含まれているため、大きな遅延がある可能性があります。更新の失敗は許容されます。しかし、あなたは別の問題を提起しました。アップデートが200ミリ秒よりも長くかかる場合、最初のアップデートが完了していないときにアップデートへの2回目のコールが発生した場合、何が起こるか分かりません。 Sharun

+0

@Klerkの場合、最も簡単な解決策は、以前の呼び出しを完了していない場合に直ちに実行されるループメソッドの先頭にガードチェックを置くことです。これは、あなたが区間をスキップすることに終わる可能性があることを意味しますが、それが大丈夫ならば、それは速く、簡単で、絶対確実です。 –