【解決方法】スレッドを正確な間隔で繰り返すにはどうすればよいですか? C#

プログラミングQA

[ad_1]

C#
 private volatile bool _pause = false;
 private ManualResetEvent _pauseEvent = new ManualResetEvent(true);
 private Thread m_thread;
 private bool _istoday = true;
 private bool _isTimer_stop = false;
 private bool _thread_start = true;

private void btn_start_Click(object sender, EventArgs e)
 {

     int timer_interval = (int)numeric_app_freequency.Value;

         timer1_Tick(sender, e);
         timer1.Interval = 60 * 1000 * timer_interval;
         timer1.Enabled = true;
         timer1.Start(); //

 }

 private void timer1_Tick(object sender, EventArgs e)
 {
     if (_thread_start == true)
       {
         _thread_start = false;
         _istoday = true;
         m_thread = new Thread(new ThreadStart(begin_thread));
         m_thread.Name = "thred_1";
         m_thread.IsBackground = true;
         m_thread.Start();

        }

 }

 private void begin_thread()
 {

     int pageNum = 1;

     while (_pauseEvent.WaitOne())
     {
         if (_istoday == true)
         {

             parse_trs(pageNum);
             pageNum++;

         }
         else
         {
             Textbox1.Text = "Work is done"; ;
             break;
         }

     }
     _autoEvent.Set();
 }

 private void parse_trs(int pageNum)
 {
     string str_pageNum = pageNum.ToString();

     string list_url = "http://somedomain.com/bbs/board.php?bo_table=funny&page=" + str_pageNum;

     WebClient client = new WebClient();
     string sourceUrl = client.DownloadString(list_url);

     HtmlAgilityPack.HtmlDocument mydoc = new HtmlAgilityPack.HtmlDocument();

     mydoc.LoadHtml(sourceUrl);


     HtmlNodeCollection tr_col = mydoc.DocumentNode.SelectNodes("/ html / body//div[@id="bo_list"]//table/tbody/tr");

     foreach (HtmlNode node in tr_col)
     {

         _pauseEvent.WaitOne();


         if (post_date == today_date)
         {

             Do work.......................................

         }
         else
         {
             _istoday = false;
             break;
         }

     }
 }

私が試したこと:

タイマーの代わりに while ループを使用しましたが、CPU が過負荷になり、アプリケーションがフリーズしてしまいました。

解決策 1

これはおそらく、スレッドの周期的またはほぼ周期的な動作を取得するための最悪の設計です。 それには多くの理由がありますが、すべてを議論する必要はありません。 新しいスレッド インスタンスの作成と開始にかかるコストは要因の 1 つですが、決して最悪ではありません。 最悪なのは、すべてを簡単に台無しにしてしまう可能性があることです。

はるかに優れた単純な解決策は、追加のスレッドを 1 つだけ作成し、アプリケーションの存続期間中ほぼすべての期間にわたってそのスレッドを実行し続けることです。 これを「無限」ループ (実際には、アプリケーションが終了しようとしているときにのみ中断されます) で実行するようにし、イベント待機ハンドル オブジェクトを使用してそのアクティビティを抑制するだけです。

通話中にそれを理解することが重要です WaitHandle.WaitOne スレッドは通過するか、特別なスレッドに置かれます。 待機状態; スイッチがオフになり、ウェイクアップされるまで実行がスケジュールされることはありません。 Thread.AbortThread.Interrupt、タイムアウト、およびその他のイベント、特に別のスレッドからの待機ハンドル オブジェクトに通知するイベント。 この方法では、スレッドは待機状態で CPU 時間を費やさず、スピン待機も定期的な状態チェックも何も行われません。

参照してください: EventWaitHandle クラス (System.Threading)[^]。

私の過去の回答をご覧ください:
コードをスレッドセーフにする[^]、
実行中のスレッドを一時停止する[^]、
スレッド内の ManualResetEvent と AutoResetEvent[^]、
Web サービスで決して終了しないジョブ/スレッド/プロセスを 1 つだけ実行する (asp.net)[^]。

ブロッキング コレクションを使用するという代替関連手法に特に注意してください。 当面の質問とは関係ありませんが、理解しておくことは重要です。

さて、タイマーによる「定期的」な繰り返しの話に戻りましょう。 このようにする必要があるかどうかはわかりません。 別の方法の 1 つは、スレッド内でコードの一部を単独で繰り返し、現在のリアルタイム時間をたとえば次のように取得することです。 System.DateTime.Now、次回実行時間の計算と呼び出し Thread.Sleep 適切な期間で。 しかし、本当にタイマーが必要な場合(これも理由はわかりませんが)、その唯一の機能は、呼び出してイベント待機ハンドルに通知することです。 EventWaitHandle.Set()これにより、このイベント ハンドル インスタンスを待機しているスレッドが起動されます。 一部のメソッドの他のほとんどの呼び出しとは異なり、この呼び出しはスレッドセーフであることに注意してください。 また、タイマー イベントは知らないスレッドで発生することにも注意してください (本当に悪いスレッドを除く) System.Windows.Forms.Timer これにより、UI スレッドでティック ハンドラーが呼び出されますが、この「軽減」が唯一の利点です。 ほとんどの場合、タイミングが壊滅的に悪いため、決して使用すべきではありません)。

どちらのテクニックも、直面する可能性のある最大の問題を解決します。 前回のタイマーティックによって引き起こされた処理がまだ完了していない場合に、何らかの処理を開始すると何が起こるでしょうか? 起こり得るすべての混乱を想像するのは難しいかもしれません。 私が提案する解決策には、この問題はまったくありません。

-SA

[ad_2]

コメント

タイトルとURLをコピーしました