これは、単なる有用な情報ではなく、専門家への質問後の質問です。 ディスカッションに招待します。
最近、幸運にもSvyaznoyの履歴書を.NET開発者の地位に送ることができました。 応答として、マルチスレッドの知識テストを行うように頼まれました。 自分をこの分野の専門家と呼ぶことはできませんが、それでも、次の要件をどのように実装するかが完全に理解できました。
JavaのFixedThreadPoolに似たC#クラスの実装が必要です。次の要件があります。
- このクラスのコンストラクターには、タスクを実行するスレッドの数を渡す必要があります。
- クラスインターフェイスはメソッドを提供する必要があります。ブール実行(タスクタスク、優先度優先)およびvoid stop()
- Taskインターフェースには、任意のスレッドで呼び出されるvoid execute()という1つのメソッドが含まれている必要があります。
- 優先度タイプは、3つの優先度の列挙です:HIGH、NORMAL、LOW。 さらに、キューから次のタスクを選択する際には、次のルールが適用されます:優先度が高の3つのタスク、優先度が通常のタスクが1つ実行され、優先度が低のタスクは実行されませんが、キューには優先度が異なるタスクが少なくとも1つあります。
- stop()メソッドが呼び出される前に、タスクは実行のためにキューに入れられ、ブール実行(タスクタスク、優先度優先)メソッドはタスクの完了を待たずにすぐにtrueを返します。 また、stop()が呼び出された後、新しいタスクは実行キューに追加されず、ブールのexecute(タスクタスク、優先度優先度)メソッドはすぐにfalseを返します。
- stop()メソッドは、現在のすべてのタスクの完了を待ちます(キューをクリアすることなく)。
タスクは、使用するプリミティブ、最も単純なスレッドですべてを実行するか、ThreadPool、TPLなどを使用するかを指定しなかったため、最も基本的な要素であるThread、ManualResetEventsなどを使用することを決定しました。 数時間で書いて送った。 今日、私は人事担当者に電話をかけ、回答を受け取りました。これは次のようなものでした:「必要なものにさえ近づいていません」。 これは私を困惑させました。コードが機能し、テストされているため、明らかな欠陥はありません。
したがって、あなたの判断で、FixedThreadPoolと関連クラスの実装を紹介します。 私はすぐに、彼らの意見では、実装に誤りがあると警告します。したがって、私の考えを基礎として取る価値はありません。 コードに関するコメント:
- タスククラス自体にタスクフローをカプセル化することにしました。
- ILogタイプの2つのパラメーターはテスト目的でのみ必要です。もちろん、これらは主要機能とは関係ありません。
- テストアプリケーションを含むプロジェクト全体は、リンクからダウンロードできます(27キロバイト): ifolderのテストプロジェクト
FixedThreadPool
/// <summary> /// , /// . /// </summary> /// <remarks> /// . /// </remarks> public sealed class FixedThreadPool { #region Constructors /// <summary> /// /// . /// </summary> /// <param name="aConcurrentTaskNumber"> /// . /// </param> /// <param name="aLog"> /// . /// </param> /// <param name="aPriorityLog"> /// . /// </param> /// <exception cref="ArgumentOutOfRangeException"> /// . /// </exception> public FixedThreadPool (int aConcurrentTaskNumber, ILog aLog = null, ILog aPriorityLog = null) { if (aConcurrentTaskNumber <= 1) { throw new ArgumentOutOfRangeException( "aConcurrentTaskNumber", " ."); } Log = aLog; PriorityLog = aPriorityLog; mConcurrentTaskNumber = aConcurrentTaskNumber; LogMessage(" ."); Thread lTaskSchedulerThread = new Thread(TaskSchedulerLogic) {Name = " ."}; lTaskSchedulerThread.Start(); LogMessage(" ."); } #endregion #region Public methods /// <summary> /// <paramref name="aTask"/> /// <paramref name="aTaskPriority"/>. /// </summary> /// <param name="aTask"> /// .. /// </param> /// <param name="aTaskPriority"> /// . /// </param> /// <returns> /// <see langword="true"/> - . /// <see langword="false"/> - , /// . /// </returns> /// <exception cref="ArgumentNullException"> /// . /// </exception> public bool Execute(Task aTask, TaskPriority aTaskPriority) { if (aTask == null) { throw new ArgumentNullException( "aTask", " ."); } LogMessage(" ."); lock (mIsStoppedLock) { if (IsStopped) { // . LogPriority(aTaskPriority, ConsoleColor.DarkGray); // . return false; } } // . EnqueueTask(aTask, aTaskPriority); LogMessage(" .", ConsoleColor.DarkYellow); return true; } /// <summary> /// , . /// . /// </summary> /// <remarks> /// /// <see cref="Execute"/> <see langword="false"/>. /// , , . /// </remarks> public void Stop() { // . lock (mIsStoppedLock) { IsStopped = true; LogMessage(" ."); } // , . LogMessage( " .", ConsoleColor.DarkRed); lock (mTaskSchedulerLock) { // mTaskSchedulerLock. Monitor.Pulse(mTaskSchedulerLock); } mPoolStoppedGate.WaitOne(); LogMessage(" .", ConsoleColor.DarkRed); } #endregion #region Private properties /// <summary> /// / , . /// </summary> /// <value> /// <see langword="true"/> - , /// . <see langword="false"/> - . /// </value> /// <remarks> /// <see cref="mIsStoppedLock"/>. /// </remarks> private bool IsStopped { get; set; } /// <summary> /// / . /// </summary> private ILog PriorityLog { get; set; } /// <summary> /// / . /// </summary> private ILog Log { get; set; } #endregion #region Private methods /// <summary> /// . . /// </summary> private void TaskSchedulerLogic() { lock (mTaskSchedulerLock) { while (true) { // , mTaskSchedulerLock. Monitor.Wait(mTaskSchedulerLock); lock (mQueuedTasksLock) { lock (mIsStoppedLock) { lock (mRunningTasksLock) { if (IsStopped && !mRunningTasks.Any() && !mQueuedTasks.Any()) { LogMessage( " ."); LogMessage(" - ."); // . mPoolStoppedGate.Set(); return; } } } } lock (mQueuedTasksLock) { if (!mQueuedTasks.Any()) { // . // . continue; } } lock (mRunningTasksLock) { if (mRunningTasks.Count >= mConcurrentTaskNumber) { // . // . continue; } } LogMessage( " .", ConsoleColor.DarkRed); // . TaskListEntry lTask = DequeueTask(); LogMessage(" - ."); // . lTask.Task.Finished += OnTaskFinished; // . lock (mRunningTasksLock) { mRunningTasks.Add(lTask); } if (lTask.TaskPriority == TaskPriority.High) { // . // . Interlocked.Increment(ref mQueuedHighPriorityTaskCounter); } else if (lTask.TaskPriority == TaskPriority.Normal) { // . // HighPriorityTaskFactor. Interlocked.Add( ref mQueuedHighPriorityTaskCounter, -HighPriorityTaskFactor); } // . lTask.Task.Execute(); LogMessage( string.Format( " - {0}.", lTask.TaskPriority), ConsoleColor.DarkYellow); lock (mRunningTasksLock) { LogMessage( string.Format( " {0} .", mRunningTasks.Count)); } } } } /// <summary> /// . /// </summary> /// <param name="aSender"> /// - . /// </param> /// <param name="aEventArgs"> /// . /// </param> private void OnTaskFinished(object aSender, EventArgs aEventArgs) { Task lSender = aSender as Task; Debug.Assert( lSender != null, " aSender ."); // , . lSender.Finished -= OnTaskFinished; // . lock (mRunningTasksLock) { // . TaskListEntry lEntry = mRunningTasks.First(aEntry => aEntry.Task == lSender); mRunningTasks.Remove(lEntry); LogMessage( string.Format(" {0} .", lEntry.TaskPriority), ConsoleColor.Red); } lock (mTaskSchedulerLock) { // mTaskSchedulerLock. Monitor.Pulse(mTaskSchedulerLock); } } /// <summary> /// <paramref name="aTask"/> . /// </summary> /// <param name="aTask"> /// , . /// </param> /// <param name="aTaskPriority"> /// . /// </param> private void EnqueueTask(Task aTask, TaskPriority aTaskPriority) { TaskListEntry lEntry = new TaskListEntry(aTask, aTaskPriority); LogPriority(aTaskPriority, ConsoleColor.Green); lock (mQueuedTasksLock) { // . mQueuedTasks.Add(lEntry); LogMessage( string.Format( " {0}", lEntry.TaskPriority), ConsoleColor.Green); // . LogMessage(" .", ConsoleColor.DarkRed); } lock (mTaskSchedulerLock) { // mTaskSchedulerLock. Monitor.Pulse(mTaskSchedulerLock); } } /// <summary> /// . /// , . /// </summary> /// <returns> /// , . /// </returns> private TaskListEntry DequeueTask() { TaskListEntry lNextTask; lock (mQueuedTasksLock) { lNextTask = FindNextTaskUsingPriorityRules(); LogPriority(lNextTask.TaskPriority, ConsoleColor.Red); LogMessage( string.Format( " {0}.", lNextTask.TaskPriority), ConsoleColor.DarkRed); mQueuedTasks.Remove(lNextTask); } lock (mTaskSchedulerLock) { // mTaskSchedulerLock. Monitor.Pulse(mTaskSchedulerLock); } return lNextTask; } /// <summary> /// . /// </summary> /// <returns> /// . /// </returns> /// <remarks> /// : /// . , , /// . , /// , , . /// , , -, /// - . /// </remarks> private TaskListEntry FindNextTaskUsingPriorityRules() { TaskListEntry lNextTask; lock (mQueuedTasksLock) { Debug.Assert( mQueuedTasks.Count > 0, " FindNextTaskUsingPriorityRules , ."); // . TaskPriority lNextTaskPriority = TaskPriority.High; // . if (mQueuedTasks.All(aEntry => aEntry.TaskPriority == TaskPriority.Low)) { // . // . lNextTaskPriority = TaskPriority.Low; } else { // . if (mQueuedTasks.Any( aEntry => aEntry.TaskPriority == TaskPriority.Normal) && (mQueuedTasks.All( aEntry => aEntry.TaskPriority != TaskPriority.High) || Interlocked.CompareExchange(ref mQueuedHighPriorityTaskCounter, 0, 0) >= HighPriorityTaskFactor)) { // // // . // . lNextTaskPriority = TaskPriority.Normal; } } lNextTask = mQueuedTasks.First( aEntry => aEntry.TaskPriority == lNextTaskPriority); } return lNextTask; } /// <summary> /// . /// </summary> /// <param name="aMessage"> /// . /// </param> /// <param name="aColor"> /// . /// </param> private void LogMessage(string aMessage, ConsoleColor aColor = ConsoleColor.Yellow) { if (Log == null) { return; } Log.WriteMessage(aMessage, aColor); } /// <summary> /// . /// </summary> /// <param name="aTaskPriority"> /// . /// </param> /// <param name="aColor"> /// . /// </param> private void LogPriority(TaskPriority aTaskPriority, ConsoleColor aColor) { if (PriorityLog == null) { return; } string lPriority = aTaskPriority == TaskPriority.High ? "H" : aTaskPriority == TaskPriority.Normal ? "N" : "L"; PriorityLog.WriteMessage(lPriority, aColor); } #endregion #region Private data /// <summary> /// , /// , , /// . /// </summary> private const int HighPriorityTaskFactor = 3; /// <summary> /// . /// . /// </summary> private readonly int mConcurrentTaskNumber; /// <summary> /// <see cref="IsStopped"/>. /// </summary> private readonly object mIsStoppedLock = new object(); /// <summary> /// . , /// . /// </summary> private readonly ManualResetEvent mPoolStoppedGate = new ManualResetEvent(false); /// <summary> /// , . /// </summary> /// <remarks> /// <see cref="mQueuedTasksLock"/>. /// </remarks> private readonly IList<TaskListEntry> mQueuedTasks = new List<TaskListEntry>(); /// <summary> /// <see cref="mQueuedTasks"/>. /// </summary> private readonly object mQueuedTasksLock = new object(); /// <summary> /// . /// </summary> /// <remarks> /// <see cref="mRunningTasksLock"/>. /// </remarks> private readonly IList<TaskListEntry> mRunningTasks = new List<TaskListEntry>(); /// <summary> /// <see cref="mRunningTasks"/>. /// </summary> private readonly object mRunningTasksLock = new object(); /// <summary> /// , / . /// </summary> private readonly object mTaskSchedulerLock = new object(); /// <summary> /// , . /// , /// <see cref="HighPriorityTaskFactor"/>. /// </summary> /// <remarks> /// /// <see cref="Interlocked"/>. /// </remarks> private int mQueuedHighPriorityTaskCounter; #endregion #region Nested type: TaskListEntry /// <summary> /// . /// </summary> /// <remarks> /// . /// </remarks> private struct TaskListEntry { #region Constructors /// <summary> /// . /// </summary> /// <param name="aTask"> /// . /// </param> /// <param name="aTaskPriority"> /// . /// </param> public TaskListEntry(Task aTask, TaskPriority aTaskPriority) { mTask = aTask; mTaskPriority = aTaskPriority; } #endregion #region Public properties /// <summary> /// . /// </summary> public Task Task { get { return mTask; } } /// <summary> /// . /// </summary> public TaskPriority TaskPriority { get { return mTaskPriority; } } #endregion #region Private data private readonly Task mTask; private readonly TaskPriority mTaskPriority; #endregion } #endregion }
タスク
/// <summary> /// <see cref="FixedThreadPool1"/>. /// </summary> public class Task { #region Constructors /// <summary> /// <see cref="FixedThreadPool1"/> /// . /// </summary> /// <param name="aTaskBody"> /// . /// </param> /// <exception cref="ArgumentNullException"> /// . /// </exception> public Task(Action aTaskBody) { if (aTaskBody == null) { throw new ArgumentNullException("aTaskBody", " ."); } TaskBody = aTaskBody; } #endregion #region Public properties /// <summary> /// / . /// </summary> public Action TaskBody { get; private set; } #endregion #region Events /// <summary> /// , . /// </summary> public event EventHandler Finished; #endregion #region Public methods /// <summary> /// . /// </summary> public void Execute() { Thread lTaskThread = new Thread( () => { // . TaskBody(); // . EventHandler lFinished = Finished; if (lFinished != null) { lFinished(this, EventArgs.Empty); } }) {Name = "Task thread."}; lTaskThread.Start(); } #endregion }
タスクの優先度
/// <summary> /// . /// </summary> public enum TaskPriority { /// <summary> /// . /// </summary> High = 0, /// <summary> /// . /// </summary> Normal, /// <summary> /// . /// </summary> Low }
エラー処理
あなたのコメントと建設的な批判に感謝します。 修正されたソリューションを公開しない場合、トピックを閉じないことにしました。 最初に、推奨事項をリストし、コードに含まれる推奨事項と含まれない推奨事項、およびその理由を説明します。
- ストリームの作成は非常に高価な操作です。 スレッドプールは、すでに作成された複数のスレッドを保存するために必要です。 これが私の主な間違いであり、明らかに、これが私の決定を確認していた技術専門家からそのような否定的な反応を引き起こしたのです。 私はあまりにも問題の条件に集中し、クラス名自体に続く要件を見落としていました。 ありがとう、 Unrul 、 iaroshenko 。 次に、プールコンストラクターで必要な数のスレッドを作成します。 Taskクラスはスレッドを作成しなくなりました。
- スケジューラスレッドは必要ありません。 実際、スレッドの作成がタスククラスからプールクラスに転送された後、タスクをキューからスレッド自体に抽出する機能をシフトできるようになりました。 ありがとう、 iaroshenko 、 romik 。
- タスクインターフェースにイベントがあってはなりません。 タスククラスはスレッドを作成しなくなったため、タスク完了イベントは本当に不要になりました。 ありがとう、 Nagg 。
- IsStoppedのロックは、通常のvolatileフィールドに置き換えることができます。 私はこれに同意しません。 volatile修飾子のおかげで、そのようなフィールドの値を読み取るコードは最新の値を受け取るというMSDNの声明にもかかわらず、そうではありません。 実際に、簡単に言うと、volatileは、コンパイラ、CLR、およびプロセッサが揮発性フィールドとその他のフィールドの読み取り/書き込みを交換しないことを保証します。 詳細はこちらをご覧ください 。 ただし、私の場合、IsStoppedロックは別のロックに必要です。 これがないと、プールが実際に停止した後に新しいタスクがキューに落ちる可能性があり、完了信号が与えられているにもかかわらずタスクフローがスタンバイ状態のままになる場合もあります。 いずれにせよ、マルチスレッドコードの少しの再保険は決して傷つきません。 これは、不規則なエラーを後でキャッチするよりも優れています。 私は口の中で泡でこの解決策を守りません。 誰かがコードに基づいて私の議論に反論できるなら、私は感謝するでしょう。 ありがとう、 elw00d 。
- 優先度キューは、ThreadPool自体のロジックとは別に実装する必要があります。 私もそうしませんでした 実際、プールには多くのコードが含まれておらず、コメントとロギングが多くあります。 しかし、それにもかかわらず、主な理由はこれではありません。 選択条件が変更されたと想像してください。 または、プールインスタンスの作成時に次のタスクを選択する原則をカスタマイズする機能を提供する必要があります。 ソートされたコレクション(キュー)の新しいクラスを作成し、それに応じて、コレクションクラスの数でプールクラスを生成する必要があります。 これは間違った決定です。 この場合、Strategyテンプレートを実装して、次のタスクを選択するためのアルゴリズムを別のクラスに移動することをお勧めします。 この場合の「セレクタ」オブジェクトは、コンストラクタに渡されます。 しかし、これは問題の状態によって必要とされないため、決定を複雑にすることはありません。 ありがとう、 elw00d 。
- インターロックされたメソッドも理由が不明です(モニターとイベントが既に使用されている場合)。 私もこの部分には触れませんでした。 インターロックされた方法により、優先度が高および通常のタスクの選択条件の違反を回避できます。 mQueuedHighPriorityTaskCounterカウンターへのアクセスにはロックがないため、万が一に備えて、Interlockedメソッドを使用して安全に再生することにしました。 おそらくコードのより深い分析は私の間違いを明らかにするでしょうが、私が言ったように、私はマルチスレッドの最大の専門家ではなく、特に安価な場合はストローを置くことを好みます。 ありがとう、 elw00d 。
- 著者がコメントで表明された欠点を解決し、再びソリューションの更新バージョンをSvyaznoyに送信した場合、非常に興味深いでしょう。 もちろん、これはコードと間接的な関係しかありませんが、それでもなお関係があります。 修正されたソリューションをメッセンジャーに送信しないと思います。 私はあなたの助けを利用したので、公平ではありません。 ほとんどの場合、この記事へのリンクを送信し、「既製のスペシャリスト」が必要か、間違いを認めて開発し、先へ進む方法を知っている人が必要かどうかを判断させます。 サポートありがとう、@ ARC_Programmer。
修正されたテストプロジェクトはここからダウンロードできます。 修正されたコード:
FixedThreadPool
// : Eshva.Threading // : FixedThreadPool.cs // GUID : 7F1EECB7-F28A-4A20-9536-26D174BCD437 // : Mike Eshva (mike@eshva.ru) // : 04.06.2012 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; namespace Eshva.Threading.Framework { /// <summary> /// , /// . /// </summary> /// <remarks> /// . /// </remarks> public sealed class FixedThreadPool { #region Constructors /// <summary> /// /// . /// </summary> /// <param name="aConcurrentTaskNumber"> /// . /// </param> /// <param name="aLog"> /// . /// </param> /// <param name="aPriorityLog"> /// . /// </param> /// <exception cref="ArgumentOutOfRangeException"> /// . /// </exception> public FixedThreadPool (int aConcurrentTaskNumber, ILog aLog = null, ILog aPriorityLog = null) { if (aConcurrentTaskNumber <= 1) { throw new ArgumentOutOfRangeException( "aConcurrentTaskNumber", " ."); } Log = aLog; PriorityLog = aPriorityLog; for (int lThreadIndex = 0; lThreadIndex < aConcurrentTaskNumber; lThreadIndex++) { string lThreadName = string.Format("Task thread #{0}", lThreadIndex); Thread lTaskThread = new Thread(TaskThreadLogic) {Name = lThreadName}; lTaskThread.Start(); } } #endregion #region Public methods /// <summary> /// <paramref name="aTask"/> /// <paramref name="aTaskPriority"/>. /// </summary> /// <param name="aTask"> /// .. /// </param> /// <param name="aTaskPriority"> /// . /// </param> /// <returns> /// <see langword="true"/> - . /// <see langword="false"/> - , /// . /// </returns> /// <exception cref="ArgumentNullException"> /// . /// </exception> public bool Execute(Task aTask, TaskPriority aTaskPriority) { if (aTask == null) { throw new ArgumentNullException( "aTask", " ."); } LogMessage(" ."); lock (mIsStoppedLock) { if (IsStopped) { // . LogPriority(aTaskPriority, ConsoleColor.DarkGray); // . return false; } } // . EnqueueTask(aTask, aTaskPriority); LogMessage(" .", ConsoleColor.DarkYellow); return true; } /// <summary> /// , . /// . /// </summary> /// <remarks> /// /// <see cref="Execute"/> <see langword="false"/>. /// , , . /// </remarks> public void Stop() { // . lock (mIsStoppedLock) { IsStopped = true; LogMessage(" ."); } // , . LogMessage( " .", ConsoleColor.DarkRed); lock (mTaskSchedulerLock) { // mTaskSchedulerLock. Monitor.PulseAll(mTaskSchedulerLock); } mPoolStoppedGate.WaitOne(); LogMessage(" .", ConsoleColor.DarkRed); } #endregion #region Private properties /// <summary> /// / , . /// </summary> /// <value> /// <see langword="true"/> - , /// . <see langword="false"/> - . /// </value> /// <remarks> /// <see cref="mIsStoppedLock"/>. /// </remarks> private bool IsStopped { get; set; } /// <summary> /// / . /// </summary> private ILog PriorityLog { get; set; } /// <summary> /// / . /// </summary> private ILog Log { get; set; } #endregion #region Private methods private void TaskThreadLogic() { lock (mTaskSchedulerLock) { while (true) { // , mTaskSchedulerLock. Monitor.Wait(mTaskSchedulerLock); lock (mQueuedTasksLock) { if (!mQueuedTasks.Any()) { lock (mIsStoppedLock) { if (IsStopped) { LogMessage( " ."); LogMessage(" - ."); // . mPoolStoppedGate.Set(); return; } } // , . // . continue; } } LogMessage( " .", ConsoleColor.DarkRed); // . TaskListEntry lTask = DequeueTask(); LogMessage(" - ."); switch (lTask.TaskPriority) { case TaskPriority.High: Interlocked.Increment(ref mQueuedHighPriorityTaskCounter); break; case TaskPriority.Normal: Interlocked.Add( ref mQueuedHighPriorityTaskCounter, -HighPriorityTaskFactor); break; } // . lTask.Task.Execute(); LogMessage( string.Format( " - {0}.", lTask.TaskPriority), ConsoleColor.DarkYellow); lock (mQueuedTasksLock) { lock (mIsStoppedLock) { if (IsStopped && !mQueuedTasks.Any()) { LogMessage( " ."); LogMessage(" - ."); // . mPoolStoppedGate.Set(); return; } } } } } } /// <summary> /// <paramref name="aTask"/> . /// </summary> /// <param name="aTask"> /// , . /// </param> /// <param name="aTaskPriority"> /// . /// </param> private void EnqueueTask(Task aTask, TaskPriority aTaskPriority) { TaskListEntry lEntry = new TaskListEntry(aTask, aTaskPriority); LogPriority(aTaskPriority, ConsoleColor.Green); lock (mQueuedTasksLock) { // . mQueuedTasks.Add(lEntry); LogMessage( string.Format( " {0}", lEntry.TaskPriority), ConsoleColor.Green); // . LogMessage(" .", ConsoleColor.DarkRed); } lock (mTaskSchedulerLock) { // mTaskSchedulerLock. Monitor.Pulse(mTaskSchedulerLock); } } /// <summary> /// . /// , . /// </summary> /// <returns> /// , . /// </returns> private TaskListEntry DequeueTask() { TaskListEntry lNextTask; lock (mQueuedTasksLock) { lNextTask = FindNextTaskUsingPriorityRules(); LogPriority(lNextTask.TaskPriority, ConsoleColor.Red); LogMessage( string.Format( " {0}.", lNextTask.TaskPriority), ConsoleColor.DarkRed); mQueuedTasks.Remove(lNextTask); } lock (mTaskSchedulerLock) { // mTaskSchedulerLock. Monitor.Pulse(mTaskSchedulerLock); } return lNextTask; } /// <summary> /// . /// </summary> /// <returns> /// . /// </returns> /// <remarks> /// : /// . , , /// . , /// , , . /// , , -, /// - . /// </remarks> private TaskListEntry FindNextTaskUsingPriorityRules() { TaskListEntry lNextTask; lock (mQueuedTasksLock) { Debug.Assert( mQueuedTasks.Count > 0, " FindNextTaskUsingPriorityRules , ."); // . TaskPriority lNextTaskPriority = TaskPriority.High; // . if (mQueuedTasks.All(aEntry => aEntry.TaskPriority == TaskPriority.Low)) { // . // . lNextTaskPriority = TaskPriority.Low; } else { // . if (mQueuedTasks.Any( aEntry => aEntry.TaskPriority == TaskPriority.Normal) && (mQueuedTasks.All( aEntry => aEntry.TaskPriority != TaskPriority.High) || Interlocked.CompareExchange(ref mQueuedHighPriorityTaskCounter, 0, 0) >= HighPriorityTaskFactor)) { // // // . // . lNextTaskPriority = TaskPriority.Normal; } } lNextTask = mQueuedTasks.First( aEntry => aEntry.TaskPriority == lNextTaskPriority); } return lNextTask; } /// <summary> /// . /// </summary> /// <param name="aMessage"> /// . /// </param> /// <param name="aColor"> /// . /// </param> private void LogMessage(string aMessage, ConsoleColor aColor = ConsoleColor.Yellow) { if (Log == null) { return; } Log.WriteMessage(aMessage, aColor); } /// <summary> /// . /// </summary> /// <param name="aTaskPriority"> /// . /// </param> /// <param name="aColor"> /// . /// </param> private void LogPriority(TaskPriority aTaskPriority, ConsoleColor aColor) { if (PriorityLog == null) { return; } string lPriority = aTaskPriority == TaskPriority.High ? "H" : aTaskPriority == TaskPriority.Normal ? "N" : "L"; PriorityLog.WriteMessage(lPriority, aColor); } #endregion #region Private data /// <summary> /// , /// , , /// . /// </summary> private const int HighPriorityTaskFactor = 3; /// <summary> /// <see cref="IsStopped"/>. /// </summary> private readonly object mIsStoppedLock = new object(); /// <summary> /// . , /// . /// </summary> private readonly ManualResetEvent mPoolStoppedGate = new ManualResetEvent(false); /// <summary> /// , . /// </summary> /// <remarks> /// <see cref="mQueuedTasksLock"/>. /// </remarks> private readonly IList<TaskListEntry> mQueuedTasks = new List<TaskListEntry>(); /// <summary> /// <see cref="mQueuedTasks"/>. /// </summary> private readonly object mQueuedTasksLock = new object(); /// <summary> /// , / . /// </summary> private readonly object mTaskSchedulerLock = new object(); /// <summary> /// , . /// , /// <see cref="HighPriorityTaskFactor"/>. /// </summary> /// <remarks> /// /// <see cref="Interlocked"/>. /// </remarks> private int mQueuedHighPriorityTaskCounter; #endregion #region Nested type: TaskListEntry /// <summary> /// . /// </summary> /// <remarks> /// . /// </remarks> private struct TaskListEntry { #region Constructors /// <summary> /// . /// </summary> /// <param name="aTask"> /// . /// </param> /// <param name="aTaskPriority"> /// . /// </param> public TaskListEntry(Task aTask, TaskPriority aTaskPriority) { mTask = aTask; mTaskPriority = aTaskPriority; } #endregion #region Public properties /// <summary> /// . /// </summary> public Task Task { get { return mTask; } } /// <summary> /// . /// </summary> public TaskPriority TaskPriority { get { return mTaskPriority; } } #endregion #region Private data private readonly Task mTask; private readonly TaskPriority mTaskPriority; #endregion } #endregion } }
タスク
// : Eshva.Threading // : Task.cs // GUID : 292467E7-4816-4407-BB9B-3309D13C8614 // : Mike Eshva (mike@eshva.ru) // : 04.06.2012 using System; namespace Eshva.Threading.Framework { /// <summary> /// <see cref="FixedThreadPool"/>. /// </summary> public class Task { #region Constructors /// <summary> /// <see cref="FixedThreadPool"/> /// . /// </summary> /// <param name="aTaskBody"> /// . /// </param> /// <exception cref="ArgumentNullException"> /// . /// </exception> public Task(Action aTaskBody) { if (aTaskBody == null) { throw new ArgumentNullException("aTaskBody", " ."); } TaskBody = aTaskBody; } #endregion #region Public methods /// <summary> /// . /// </summary> public void Execute() { TaskBody(); } #endregion #region Private properties /// <summary> /// / . /// </summary> private Action TaskBody { get; set; } #endregion } }