2009-06-10 20 views
1

誰かがシングルトンについて私を裏返す前に、このインスタンスでは、コード全体でこのオブジェクトを広く使用しているシングルトンを持っていることが理にかなっています。私は聞きたいですが、私はこれがこの投稿の焦点では​​ないことを願っています。スレッディングとシングルトン

私はクラススケジューラへの参照を失っており、内部にはもはや起動しないタイマーティックがあります。これはシングルトンの方法で使用されていて、参照が失われてGCであるためですか?それは他のクラス

ApplicationContext.Current.Scheduler.Add(DateTime.Now.AddSeconds(1), ResetBackColor); 

ApplicationContextで、次の方法でアクセスされ

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows.Forms; 

namespace MessageQueueInterface 
{ 
    public class Scheduler 
    { 
     private const int _interval = 1000; 
     private readonly Dictionary<DateTime, Action> _scheduledTasks = new Dictionary<DateTime, Action>(); 
     private readonly Timer _mainTimer; 

     public Scheduler() 
     { 
      _mainTimer = new Timer(); 
      _mainTimer.Interval = _interval; 
      _mainTimer.Tick += MainTimer_Tick; 
      _mainTimer.Start(); 
     } 

     void MainTimer_Tick(object sender, EventArgs e) 
     { 
      CheckStatus(); 
     } 

     public void Add(DateTime timeToFire, Action action) 
     { 
      lock (_scheduledTasks) 
      { 
       if (!_scheduledTasks.Keys.Contains(timeToFire)) 
       { 
        _scheduledTasks.Add(timeToFire, action); 
       } 
      } 
     } 

     public void CheckStatus() 
     { 
      Dictionary<DateTime, Action> scheduledTasksToRemove = new Dictionary<DateTime, Action>(); 
      lock (_scheduledTasks) 
      { 
       foreach (KeyValuePair<DateTime, Action> scheduledTask in _scheduledTasks) 
       { 
        if (DateTime.Now >= scheduledTask.Key) 
        { 
         scheduledTask.Value.Invoke(); 
         scheduledTasksToRemove.Add(scheduledTask.Key, scheduledTask.Value); 
        } 
       } 
      } 
      foreach (KeyValuePair<DateTime, Action> pair in scheduledTasksToRemove) 
      { 
       _scheduledTasks.Remove(pair.Key); 
      } 
     } 
    } 
} 

私のシングルトンである私は、datetimeオブジェクトは辞書のための最高のKEYではないことを承知していますが、それは私のここの目的に合っています

ここはシングルトンです

public class ApplicationContext 
{ 
    private static ApplicationContext _context; 
    private Scheduler _scheduler; 

    public Scheduler Scheduler 
    { 
     get { return _scheduler; } 
    } 

    private void SetProperties() 
    { 
     _scheduler = new Scheduler(); 
    } 

    public static ApplicationContext Current 
    { 
     get 
     { 
      if (_context == null) 
      { 
       _context = new ApplicationContext(); 
       _context.SetProperties(); 

      } 
      return _context; 
     } 
    } 
} 
+0

re:singletons:いつから「このオブジェクトは広く使用されていましたか」を意味する「これはシングルトンでなければならない」という意味ですか?多くの場合、それは「それは(シングルトンではなく)グローバルでなければなりません」と、おそらく「あなたがリファクタリングする必要がある」、または暗示、あるいはいくつかのケースでは、「ちょうどそれを吸うと、オブジェクトへの周りの参照を渡す」 – jalf

+0

はです意味しますあなたのアプリケーションはマルチスレッドですか? –

+4

あなたがシングルトンを打ち負かすことについて免責を逃したと思います。これはシングルトンのディスカッションスレッドではありません。 – JoshJordan

答えて

3

投稿したクラスがあなたのシングルトンクラスではないようです。そのコードはもっと役に立ちます。

いずれにしても、タイマーが有効範囲外になりGC'edされた場合は、イベントの発生を停止します。スケジューラがすぐに範囲外に落ち、そのときとGCが発生したときの間にちょうど遅延が存在する可能性があります。

あなたのシングルトンコードを投稿すると、私や他の誰かがより具体的な回答をすることができます。シングルトンクラスの単純さを考えると

編集

、私に飛び出すだけの潜在的な問題はCurrent財産上の競合状態です。あなたが何もロックしていないとすれば、ヌルであると同時にCurrentプロパティにアクセスする2つのスレッドは、潜在的に異なる参照で終わる可能性があり、最後に設定されたものはスコープが拡張される参照を持つ唯一のものになりますプロパティゲッターそのものの範囲を超えています。

単純な同期objectインスタンスを静的メンバーとして作成し、ゲッターでロックすることをお勧めします。これにより、その状態が上がるのを防ぐことができます。

パラメータのないコンストラクタや宣言の時点でも変数を初期化するのではなく、SetProperties()メソッドの目的は何ですか?このような関数を持つと、新しいSchedulerオブジェクトを作成して既存のオブジェクトを放棄する可能性があります。

+0

にシングルトンが添付されています –

+0

あなたとアダムの競合状態は正しいと思いますので、ゲッターの周りにロックを投げます静的ロックオブジェクトで十分でしょうか? –

+0

Adamさん、ありがとうございました –

1

シングルトン自体のコードを投稿していないので、問題があるかどうかは言い難いです。しかし、オブジェクトが静的変数(またはスタック上の何か)から到達可能である限り、GC'edされるべきではありません。あなたの問題は何か他の何かを意味します。

私は、オブジェクトに複数のスレッドがアクセスしていると仮定して、いくつかの同期の問題を疑うでしょう。

2

あなたは問題がスケジューラ()へのあなたのグローバル/静的ポインタがNULLになることであると言っていますか?その場合、その参照が失敗している間にその参照を操作するコードを理解する必要があります。

私はいくつかのフィードバックを持っています... _scheduledTasks.Remove()への呼び出しは、競合状態がリストを変更しないようにロック内で発生する必要があります。また、scheduledTask.Value.Invoke()への呼び出しは、Invokeを実装するときにそのロック内の別の作業項目をキューに入れないように、ロック外で実行する必要があります。私は、ロックを離れる前に、適切なタスクをスタックのローカルリストに移動し、そのリストからタスクを実行することでこれを行います。

次に、ローカルリストにタスクが残っていて、それらがリークする可能性がある場合、Invoke()呼び出しが例外をスローするとどうなるかを考えてください。例外を捕捉/呑み込むことによって、またはロックが取り上げられるたびにキューから1つのタスクを引き出すことによってのみ処理できます。

+0

ありがとうフランク、私はすべての変更を提案した、私は少し会議のために離れて、私が戻ったときにテストします。 次のMcAden私はフォームの代わりにスレッドを使用しました –

0

System.Windows.Forms.Timerは、それが奇数回でGC'dを取得するのが好きということで非常に信頼性がありません。

ではなく、System.Threading.Timerを使用してみてください。

+0

フォームタイマーも嫌いですが、これはフォームSTAプロジェクトであるため不確実でした –

0

は、通常のWinFormsプログラムアプリケーションですか?

System.Windows.Forms.Timerは、プログラムのメッセージループ上のタイマーメッセージを待ち受けます。あなたがプログラムがWinFormsでない場合や、UIスレッドで多くの作業を行っている場合は、おそらくSystem.Timers.Timerを使用してください。複数のスレッドでイベントを起動できることに注意してください。 here