2011-12-04 14 views
0

私はモニタリングのためのGUIアプリケーションを書いています。私はそれについてのいくつかのアドバイスをしたいと思います。基本的にすべてのアプリケーションは、何分も離れていないサーバーに接続し、何かが変更されたかどうかを確認し、変更があればそれを受け取り、変更に応じてローカルデータベースを更新します。変更を監視するためのアプリケーション

私の最初のアイデアは:

  1. は(オン/オフ監視)]チェックボックスを持っています。クリックすると(チェックされている場合)、タイマーが開始されます。
  2. Timerは、TickメソッドでBackgroundWorkerを起動します。
  3. WorkDoneハンドラメソッドのメソッドが取得する/接続情報のもの
  4. a)はWorkDoneハンドラメソッドのバックグラウンドワーカーから情報を取得し、それ Bとのローカルアップデートを行いんDoWork)は、カスタムイベント「の一つ以上をトリガーSomethingChanged "変化に応じて。 EventListenersはそこからローカル更新を処理します。

私の主な問題は、WorkerをFormに追加してからWorkerをFormに追加したときに、別のスレッドにあります(その正しい説明ですか?)、同様の問題が発生します。私はデリゲートについて読んでいましたが、いつ、どのように使うべきか、それが本当に最初に必要なのかどうかはまだ分かりません。 bgWorkerとTimerの両方が必要ですか?私はカスタムイベントが必要ですか、またはスイッチ(結果)を使ってworkDone内のすべての作業を行うことはできますか?この一般的な原則は最初は良いですか?何か良いことがあり、私はホイールを再発明していますか?前もって感謝します!

答えて

2

アーキテクチャの観点から:

アプリケーションのメッセージキューのデカップルビット。 Windows Formsアプリケーションでは、Windowsが作成して管理するメッセージキューに依存することができます。 Google for PostMessage/GetMessageなど。これは一般的に「メッセージパッシング」と呼ばれます。あなたのアプリの

典型的なArcitecture

  • 一部はキューに要求
  • のアプリのいくつかの他の部分はキューから要求を「プル」との結果を書き込み「プッシュ」 2番目のキュー。
  • 最初の部分は、2番目の「結果」キューから要求を「プル」してユーザーに表示できます。

だから、次のようになります。

アプリケーション - >要求QUEUE - >処理エンジン - > RESULTSのQUEUE - >アプリケーション

処理エンジンは同じアプリで可能性があり、同じスレッドまたは異なるスレッド/プロセス(または別のマシン)で実行されます。

単純なキューを使用することができます(たとえば、ロックを使用してアクセスする場合はQueue<string>())、複雑性や複雑性/機能性の高いキューを増やすことができます。素朴な戦略や他のソリューションとの

問題...考えるべき事:

  1. 古いものがまだ完了していない間、あなたは新しい要求を行う場合はどうなりますか?
  2. エラーが発生した場合はどうなりますか?エラーがインラインで欲しいですか?エラーのために別のキューを使用できますか?
  3. 再試行しますか?
  4. メッセージが失われた場合はどうなりますか? (つまり、リクエストはプッシュされましたが、応答はありません...)トランザクションキュー等

サンプルコード

object oLock = new object(); 
    Queue<string> requests = new Queue<string>(); 
    Queue<string> responses = new Queue<string>(); 
    Thread mThread; 
    AutoResetEvent mEvent = new AutoResetEvent(false); 

    public Form1() 
    { 
     InitializeComponent(); 
     mThread = new Thread(ProcessingEngine); 
     mThread.IsBackground = true; 
     mThread.Start(); 
    } 

    private void ProcessingEngine() 
    { 
     string result; 
     string request = null; 

     while (true) 
     { 
      try 
      { 
       mEvent.WaitOne(); 

       lock (oLock) 
       { 
        request = requests.Dequeue(); 
       } 

       var wc = new WebClient(); 
       result = wc.DownloadString(request); 

       lock (oLock) 
       { 
        responses.Enqueue(result); 
       } 
      } 
      catch (Exception ex) 
      { 
       lock (oLock) 
       { 
        responses.Enqueue(ex.ToString()); 
       } 
      } 
     } 
    } 


    private void timer1_Tick(object sender, EventArgs e) 
    { 
     lock (oLock) 
     { 
      //Stick in a new request 
      requests.Enqueue("http://yahoo.com"); 

      //Allow thread to start work 
      mEvent.Set(); 

      //Check if a response has arrived 
      if (responses.Any()) 
      { 
       var result = responses.Dequeue(); 
       listBox1.Items.Add(result.Substring(1,200)); 
      } 
     } 
    } 
} 
0

あなたがSystem.Windows.Forms.Timer代わりのSystem.Threading.Timerを使用している場合は、あなたのTickハンドラはフォームのメッセージループから呼び出されると、あなたがすべてのコントロールへのフルアクセスを持っているだろう - bgWorker.RunWorkerAsync()を呼び出しても安全になります。結果を取得する場合 - RunWorkerCompletedもメッセージループスレッドから呼び出され、ここでUIを安全に更新できます。

+1

-1があります。これによりスケーラビリティが損なわれ、スレッドが一時的にタイムアウトすると、タイムアウトが発生するまでUIがブロックされますが、これは悪いことです。 Threading.Timerを使用すると、別のスレッドでの実行が可能になり、次にUIの更新だけをメインスレッド(ウィンドウ上のInvokeメソッド)に戻して呼び出すことができます。 – TomTom

+0

どうしてですか? RunWorkerAsyncが目立つ時間にブロックされているのをまだ見ていないのですが、Threading.Timer.Tickから直接UIを更新することはできず、Timerで 'Invoke'を使用すると' RunWorkerCompleted'から更新するのと全く同じ結果になります。 DoWorkは独自のスレッドで実行されるので、なぜUIがブロックされると思うか説明してください。 – MagnatLU

+0

Comp投票、このようにすることに何も問題はありません。ブロッキングは一切発生せず、ビジー状態のBGWを実行しようとすると例外が発生します。どちらの種類のタイマーでも。少なくとも、スレッドが多すぎることに対するOPの懸念が緩和されます。 –

0

解決方法は簡単です。メインスレッドに戻ってください。これはwinformコントロールのInvokeメソッドです。これは、基本的にUIスレッドへの実行のためにスレッドを変更し、UIを操作できるようにします。

「ブロックする」(つまり、コントロールごとに1回ではなく、ニュースがあるときに1回)。

関連する問題