0

VisualStudio2010を使用して.NETWindowsフォームアプリケーションに取り組んでいます。

このアプリケーションでは、基礎となるデータ送信のために4つのバックグラウンドスレッドが必要です。4つのスレッドがすべて終了すると、4つのスレッドを使用して、基礎となる4つのデータ送信の別のラウンドが再開されます。

フォームUIは常に応答性が高い必要があります。私の問題は次のとおりです。4つのスレッドの実行をどのように制御できますか?Like:すべてのスレッドが終了したことをどうやって知ることができますか?揮発性のグローバルカウンターを使用していますか?

4

2 に答える 2

2

.NET 4 は親切にもクラスTaskを提供し、高レベルの非同期 API の統合に関連しています。したがって、BackgroundWorker ベースのデザインからタスク ベースのデザインに安全に切り替えることができ、すべてのタスクが終了するまで待つのがいかに簡単かがわかりますTask.Factory.ContinueWhenAll

非同期タスク - タスクによる非同期プログラミングの簡素化を参照してください。

于 2012-10-11T05:47:55.490 に答える
1

特に 4 つのスレッドの使用に関する質問に答えるために、BackgroundWorker を使用した簡単なスケッチを以下に示します。ここでの考え方は、4 つのタスクをセットアップし、実行中のタスクの数を追跡し、すべてのタスクが完了したら再起動するというものです。volatile と interlocked の説明については、Stack Overflow の質問Volatile vs. Interlocked vs. lockを参照してください。

これにより、求めているもの (4 つのスレッド、レスポンシブ UI) が得られますが、エラー処理は行われず、他の問題が発生する可能性があります。1 つの BackgroundWorker がハングする可能性はありますか (「データ転送」がうまくいかない可能性があります)、その場合、悪い状態になりますか?

public partial class Form1 : Form  {
    private int workersRunning = 0;
    private List<BackgroundWorker> workers = new List<BackgroundWorker>();

    public Form1()  {
        InitializeComponent();
        for (int i = 0; i < 4; i++)  {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(this.worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.worker_RunWorkerCompleted);
            workers.Add(worker);
        }
    }

    private void button1_Click(object sender, EventArgs e) {
        this.StartWork();
    }

    private void StartWork() {
        workers.ForEach(worker => worker.RunWorkerAsync());
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){
        Interlocked.Decrement(ref workersRunning);
        Console.WriteLine("Worker reported completion from thread id " + e.Result);
        if(this.workersRunning == 0) {
            Console.WriteLine("All workers are done. Start again");
            this.StartWork();
        }  else  {
            Console.WriteLine(this.workersRunning + " workers are still running.");
        }
    }

    void worker_DoWork(object sender, DoWorkEventArgs e) {
        Interlocked.Increment(ref workersRunning);
        int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Doing work on thread #" + threadId);

        Thread.Sleep(new Random().Next(2000, 5000));

        e.Result = "Work done on thread id " + threadId;
    }
}
于 2012-10-10T05:14:02.633 に答える