web-dev-qa-db-ja.com

C#でスレッドを定義、開始、停止する最良の方法

スレッドが少なく、常に実行されている小さなプログラムを作成しています。ある時点で、そのうちの1つを停止し、その後、ランダムな期間を置いてから再開したい場合があります。最初に、スレッドを定義する最良の方法は何ですか、これが私のコードです

private void startCheckCommandThread() {
        isRunning = true;
        //commandThread = new Thread(checkForCommand);
        //commandThread.IsBackground = true;
        //commandThread.Start();

        new Thread(() => {
            Thread.CurrentThread.IsBackground = true;
            checkForCommand();
        }).Start();
    }

コメントされた方法、または他の方法?そして、ここに私がそれらを停止して再起動する方法があります:

// get condition variable
if (condition) {
    isRunning = false;
    // here it must be 100% guaranteed that the Thread will stop
} else {
    startCheckCommandThread();
}

それで、それを行うための最良の方法は何ですか、主に私は安定性(エラー防止を意味する)と最大パフォーマンス(できるだけ低いCPU使用率と可能な限り少ないメモリ割り当て)について尋ねていますか?

6
Skaidar

スレッドが少なく、常に実行されている小さなプログラムを作成しています。ある時点で、そのうちの1つを停止し、その後、ランダムな期間を置いてから再開したい場合があります。スレッドを作成する最良の方法は何ですか?

最善の方法は、まったく行わないことです。別のプログラムと並行して実行する必要がある作業がある場合、ベストプラクティスは別のプロセスを開始するです。非同期で実行する必要がある作業がある場合は、Task Parallel Libraryを使用して、スレッドを管理します。

スレッドは、ほとんどのタスクにとって単に粒度の単位が間違っています。スレッドはworkers;です。 workersを管理するのではなく、代わりにtasksを管理します。 TPLに必要なワーカーの数を計算させます。

ほとんど私は安定性について尋ねています(エラー防止を意味します)

スレッド化コードを正しく実行することは悪名高い。コヒーレンシ、メモリバリア、非アトミックな読み取りと書き込み、デッドロック、ライブロックなどを心配する必要があります。そのため、プロセスの使用がはるかに優れています。

すべてを1つのプロセスに保持する必要がある場合は、使用可能な最高レベルツールを使用します。この場合も、スレッドを直接操作しないでください。非同期の作業がある場合は、TPLを使用してください。その作業の一部をキャンセルする必要がある場合は、キャンセルトークンを使用してください。スレッドを直接制御しないでください。あなたはそれを誤解するでしょう。

なんらかの理由でTPLを使用したくないが、スレッドを直接使用したい場合は、スレッドが明確に定義された、慎重にテストされたチャネルを介して通信するスキームを構築して、コードを記述します。専門家によるレビュー。緊急時を除いて、スレッドを中止したくない場合があります。これを行うと、異常な方法でデータ構造が破損する可能性があります。シャットダウンするスレッドが必要な場合は、注意深く設計され、注意深く実装されたシステムを使用して、あるスレッドがシャットダウンのタイミングであることを別のスレッドに明確に通知し、そのスレッドを完全にシャットダウンする必要があります。

および最大のパフォーマンス(可能な限り低いCPU使用率、および可能な限り少ないメモリ割り当て)?

「CPU使用率を低く保つためにスレッドを使いたい」と人々が言う理由がわかりません。スレッドは、CPU使用率を維持するために存在しますhigh。あなたはそれらのCPUにかなりのお金を払った。それらを使用してください!理想的な状況はマシンのすべてのCPUが常に100%になる有用な作業を行うことです。あなたの目標は、労働者が95%の時間アイドルであった工場を建設することであったとは言わないでしょう、それで、なぜあなたはプログラムに対して同じことをするのですか?

スレッドは、CPU使用率を高く維持します。それが賢明な場合は、CPUにバインドされた作業の1つのスレッドを各CPUに割り当て、問題の作業以外に、そのCPUに他に何もしないを実行させるためです。あなたはそれを投げます。 CPUより多くのCPUバウンド作業があり、それを処理するスレッドが多い場合、CPUはスレッド間で切り替えを繰り返すことになり、すべての効率が低下します。

メモリの割り当てを避けたい場合は、スレッド数をできるだけ少なくしてください。スレッドは、割り当て可能なメモリ使用量が最も多いリソースです。デフォルトでは、それぞれがスタックの100万バイトのアドレス空間を消費します。

29
Eric Lippert

スレッドを開始する2つの方法については、おおむね同等であるため、ラムダを使用するかどうかが問題になります。

スレッドを停止するための最もエラーのない方法は、フィールド値の変更をチェックすることです。これは、メモリバリアを使用して実行できます。たとえば、lockステートメントを使用すると、モニターが自動的にメモリバリアを提供します。スレッドを同期する最も簡単な方法は、ブール型フィールドのすべてのアクセスと変更にロックステートメントを使用することです。フィールドは、停止するスレッドに関連付けられたオブジェクトに含まれます。

変数が変更されたら、スレッドで実行されている最上位のメソッドから戻ることにより、スレッドを終了します。

ほとんどの開発者はスレッドを「再利用」しません。それを終了すると、消えてしまいます-新しいものを作成する必要があります。スレッドに関連付けられたオブジェクトを再利用できます。スレッドを保持し、必要になるまで中断することもできますが、中断されている間はスレッドがリソースを浪費しているため、一般にこれは設計が悪いと見なされます。また、待機中にサイクルを燃やさないようにブロックする必要があります。

最大のパフォーマンスに関心がある場合は、Interlockedを使用した同期を確認できます。これはより高速ですが、使いにくいです。マルチスレッドを開始するだけの場合は使用しないでください。スレッディングチュートリアルには、このWebサイトをお勧めします。 C#のスレッディング

4
Frank Hileman

スレッドを管理する最善の方法は、それを行わないことです。

スレッドの使用は目的ではなく、目的を達成するための手段です。 並行性。 C#では、非同期/待機、または(他の人が言及しているように)ラムダ式(最も一般的にはPLINQを介して)によって、直接スレッド管理なしで並行性を実現します。

スレッドを開始および停止するには、コストがかかり、低速であり、可用性に依存します。代わりに、上記のアプローチは事前に割り当てられたスレッドのプールを使用します。リソースは、スレッド管理の経験が豊富な人々によって記述されたコードによって、プロセスのセットアップおよびティアダウン時に整理されます。

また、プラットフォーム開発者や、適切な経験を持つ実物大のテストチームにもアクセスできます。アプリケーション開発チームがこれに対応できるとは考えられません。

2
Peter Wone