5

メイン UI スレッドと 4 つのタスクで構成される WinForms アプリケーションがあります。私のメイン フォームには、次のようなプライベート メンバー レベル変数があります。

private bool keepThreadsRunning = false;

メインフォームの Load() イベントには、次のものがあります。

keepThreadsRunning = true;
var task1Worker = Task.Factory.StartNew(() => DoStuff1());
var task2Worker = Task.Factory.StartNew(() => DoStuff2());
var task3Worker = Task.Factory.StartNew(() => DoStuff3());
var task4Worker = Task.Factory.StartNew(() => DoStuff4());

各 DoStuff() メソッドの内部には、基本的に次のものがあります。

while (keepThreadsRunning)
{
  // do work here
  Thread.Sleep(30000); // a couple of my tasks only need to run every 30 seconds or so
}

最後に、私の Form_Closing() イベント ハンドラーには、次のものがあります。

keepThreadsRunning = false;
this.Close();

タスク マネージャーでアプリケーションを確認すると、フォームを閉じるとプロセスが終了しているように見えますが、4 つのタスクについて少し混乱しています。this.Close() への私の呼び出しは本当にそれらのタスクを終了させますか (発生時に Thread.Sleep() 呼び出しにある場合でも)? そして、私が今コーディングしている方法よりも、これを達成するためのより良い方法はありますか?

編集 - タスクのキャンセル (アプリの終了時) について簡単に調べましたが、タスクがキャンセルされたかどうかを判断するために定期的にキャンセル トークンをチェックする必要があることを理解しています。一部のタスクを 30 秒ごとに実行する必要があることを考えると、その 30 秒待機 (現在は Thread.Sleep()) を実装する方法がわかりませんでしたが、タスクはキャンセル トークンをチェックしています。

4

3 に答える 3

3

ブール値の andThread.Sleep()を使用するのではなく、次のように作成されたWaitHandle、具体的にはManualResetEventを使用します。

var threadTerminationHandle = new ManualResetEvent(false);

あなたのスレッドで:

do {
  // do work here
} while (!threadTerminationHandle.WaitOne(TimeSpan.FromSeconds(30))

これは、WaitHandle が設定されるか、30 秒が経過するまで、どちらか早い方まで待機します。

あなたのフォームで:

threadTerminationHandle.Set();
Close();
于 2012-09-21T14:21:15.277 に答える
2

まず、メイン UI スレッドを閉じると、他のタスクが終了します。それらを実行し続ける必要がある場合は、別のコンソール アプリケーションまたは Windows サービスで実行することを検討してください。

実行する必要があるメソッドの実行が終了するまでフォームを閉じるのを遅らせる方法を見つけたとしても、これはエンド ユーザーが希望する方法でフォームを閉じた場合にのみ機能します。アプリケーションを閉じる方法の 1 つであるため、これが機能するという保証はありません。

x 秒ごとに非同期でメソッドを実行するには、次のようにタイマーを使用できます。

using System;
using System.Timers;
using System.Windows.Forms;

namespace WindowsFormsApplication3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var timer1 = new System.Timers.Timer { Interval = 30000, Enabled = true };
            var timer2 = new System.Timers.Timer { Interval = 20000, Enabled = true };
            var timer3 = new System.Timers.Timer { Interval = 10000, Enabled = true };
            var timer4 = new System.Timers.Timer { Interval = 5000, Enabled = true };

            timer1.Elapsed += timer1_Elapsed;
            timer2.Elapsed += timer2_Elapsed;
            timer3.Elapsed += timer3_Elapsed;
            timer4.Elapsed += timer4_Elapsed;
        }

        void timer4_Elapsed(object sender, ElapsedEventArgs e)
        {
            //do work here
        }

        void timer3_Elapsed(object sender, ElapsedEventArgs e)
        {
            //do work here
        }

        void timer2_Elapsed(object sender, ElapsedEventArgs e)
        {
            //do work here
        }

        void timer1_Elapsed(object sender, ElapsedEventArgs e)
        {
            //do work here
        }
    }
}
于 2012-09-21T14:25:25.203 に答える
2

アプリケーションを閉じると、タスクはスレッド プールのバックグラウンド スレッドで処理されるため、それに応じてタスクが閉じられます。そのため、定期的にキャンセル トークンをチェックして、キャンセルされたかどうかを判断する必要はありません。

于 2012-09-21T18:00:28.477 に答える