9

私は自分の仕事に多くの設計要件があるスレッドプールの設計を考え出そうとしています。これは、ソフトウェアを動作させるための実際の問題であり、難しい作業です。私は実用的な実装を持っていますが、これをSOに投げて、人々がどのような興味深いアイデアを思い付くことができるかを見て、私の実装と比較して、それがどのように積み重なるかを確認したいと思います。私はできる限り要件に具体的にしようとしました。

スレッドプールは一連のタスクを実行する必要があります。タスクは、短時間実行(<1秒)または長時間実行(数時間または数日)にすることができます。各タスクには関連する優先度があります(1=非常に低いから5=非常に高い)。タスクは他のタスクの実行中にいつでも到着する可能性があるため、タスクが到着すると、スレッドプールはこれらを取得し、スレッドが使用可能になったときにスケジュールする必要があります。

タスクの優先度は、タスクの長さに完全に依存しません。実際、タスクを実行するだけで、タスクの実行にかかる時間を知ることは不可能です。

一部のタスクはCPUバウンドですが、一部はIOバウンドです。特定のタスクが何であるかを事前に知ることは不可能です(ただし、タスクの実行中に検出できる可能性があると思います)。

スレッドプールの主な目標は、スループットを最大化することです。スレッドプールは、コンピューターのリソースを効果的に使用する必要があります。理想的には、CPUにバインドされたタスクの場合、アクティブなスレッドの数はCPUの数と等しくなります。IOバウンドタスクの場合、ブロッキングがスループットに過度に影響しないように、CPUよりも多くのスレッドを割り当てる必要があります。ロックの使用を最小限に抑え、スレッドセーフ/高速コンテナを使用することが重要です。

一般に、CPU優先度の高いタスクを実行する必要があります(参照:SetThreadPriority)。優先度の低いタスクは、優先度の高いタスクの実行を「ブロック」してはなりません。したがって、優先度の低いタスクがすべて実行されているときに優先度の高いタスクが実行されると、優先度の高いタスクが実行されます。

タスクには、「最大実行タスク」パラメーターが関連付けられています。各タイプのタスクは、一度に最大でこの数のタスクの同時インスタンスのみを実行できます。たとえば、キュ​​ーに次のタスクがあるとします。

  • A-1000インスタンス-低優先度-最大タスク1
  • B-1000インスタンス-低優先度-最大タスク1
  • C-1000インスタンス-低優先度-最大タスク1

動作する実装は、(最大で)1 A、1 B、および1Cしか同時に実行できませんでした。

Windows XP、Server 2003、Vista、およびServer 2008(最新のサービスパック)で実行する必要があります。


参考までに、次のインターフェイスを使用する場合があります。

namespace ThreadPool
{
    class Task
    {
    public:
        Task();     
        void run();
    };

    class ThreadPool
    {    
    public:
        ThreadPool();
        ~ThreadPool();

        void run(Task *inst);
        void stop();
    };
}
4

5 に答える 5

5

では、このための基本的な構成要素として何を選択するのでしょうか。Windowsには、有望に見える2つのビルディングブロックがあります。-I/ O完了ポート(IOCP)と非同期プロシージャコール(APC)。これらは両方とも、明示的なロックを実行する必要がなく、スケジューラーなどの場所で一定量の組み込みOSサポートを使用してFIFOキューイングを提供します(たとえば、IOCPは一部のコンテキストスイッチを回避できます)。

APCの方が少し適しているかもしれませんが、APCは完全に「透明」ではないため、少し注意する必要があります。作業項目がアラート可能な待機(:: SleepEx、:: WaitForXxxObjectExなど)を実行し、誤ってAPCをスレッドにディスパッチした場合、新しくディスパッチされたAPCがスレッドを引き継ぎ、新しいAPCが終了した。これは同時実行性の要件に悪影響を及ぼし、スタックオーバーフローが発生する可能性が高くなります。

于 2008-09-02T18:51:57.673 に答える
1

Windows XP、Server 2003、Vista、およびServer 2008(最新のサービスパック)で実行する必要があります。

システムの組み込みスレッドプールのどの機能が、それらをタスクに不適切にしますか?XPおよび2003をターゲットにする場合、新しい光沢のあるVista / 2008プールを使用することはできませんが、QueueUserWorkItemおよびその仲間を使用することはできます。

于 2008-09-01T21:58:55.750 に答える
0

@DrPizza-これは非常に良い質問であり、問​​題の核心に迫る質問です。QueueUserWorkItemとWindowsNTスレッドプールが除外された理由はいくつかあります(ただし、Vistaのものはおそらく数年で面白そうに見えます)。

まず、スレッドの起動と停止をより細かく制御する必要がありました。NTスレッドプールは、タスクが短期間のものであると考えた場合、新しいスレッドを開始することを躊躇していると聞いています。WT_EXECUTELONGFUNCTIONを使用することもできますが、タスクが長いか短いかは実際にはわかりません。

第2に、スレッドプールが実行時間の長い、優先度の低いタスクで既にいっぱいになっている場合、優先度の高いタスクがタイムリーに実行される可能性はありません。NTスレッドプールにはタスクの優先順位の実際の概念がないため、QueueUserWorkItemを実行して、「ちなみに、これをすぐに実行する」と言うことはできません。

第三に、(MSDNによると)NTスレッドプールはSTAアパートメントモデルと互換性がありません。これが何を意味するのかはよくわかりませんが、すべてのワーカースレッドはSTAで実行されます。

于 2008-09-01T22:18:26.500 に答える
0

@DrPizza-これは非常に良い質問であり、問​​題の核心に迫る質問です。QueueUserWorkItemとWindowsNTスレッドプールが除外された理由はいくつかあります(ただし、Vistaのものはおそらく数年で面白そうに見えます)。

ええ、Vistaではかなり強化されたようですが、今では非常に用途が広いです。

OK、優先順位をどのように機能させたいかについては、まだ少しわかりません。プールが現在、最大同時実行数が1で優先度が低いタイプAのタスクを実行していて、タイプA(および最大同時実行数1)の新しいタスクが与えられているが、今回は優先度が高い場合は、どうすればよいですか? ?

現在実行中のAを一時停止するのは面倒です(新しいタスクが実行する必要のあるロックを保持し、システムをデッドロックさせる可能性があります)。2番目のスレッドを生成して、一緒に実行させることはできません(許可される同時実行性は1つだけです)。ただし、ランタイムには制限がなく、優先度の低いタスクが優先度の高いタスクをブロックできるため、優先度の低いタスクが完了するまで待つことはできません。

私の推測では、あなたが求めているのは後者の行動ですか?

于 2008-09-01T22:37:18.763 に答える
0

@DrPizza:

OK、優先順位をどのように機能させたいかについては、まだ少しわかりません。プールが現在、最大同時実行数が1で優先度が低いタイプAのタスクを実行していて、タイプA(および最大同時実行数1)の新しいタスクが与えられているが、今回は優先度が高い場合は、どうすればよいですか? ?

これは少しトリッキーなものですが、この場合は、優先度の低いタスクを実行して完了するだけで十分だと思います。通常、スレッドの優先度が異なる同じタイプのタスクは多くありません。私たちのモデルでは、(これとは異なる理由で)特定の明確に定義されたポイントでタスクを安全に停止して後で再開することが実際に可能ですが、これによって生じる複雑さはおそらくリスクに見合う価値はありません。

通常、異なるタイプのタスクのみが異なる優先順位を持ちます。例えば:

  • タスク-1000インスタンス-低優先度
  • Bタスク-1000インスタンス-高優先度

Aタスクが実行され、実行されていて、Bタスクが到着したとすると、Bタスクを多かれ少なかれすぐに実行できるようにする必要があります。

于 2008-09-01T22:46:13.500 に答える