Skip to content

Work Control

ZjzMisaka edited this page Dec 24, 2024 · 2 revisions

クイックスタート

概要

Pause(...)
スレッドプールまたはタスクを一時停止します。引数として work id(s) を使用できます。
Resume(...)
スレッドプールまたはタスクを再開します。引数として work id(s) を使用できます。
Stop(...)
スレッドプールまたはタスクを停止します。引数として work id(s)強制停止フラグ を使用できます。
Wait[Async](...)
スレッドプールまたはタスクの完了を待機します。引数として work id(s) を使用できます。
Fetch[Async](...)
タスクの結果を取得します。引数として work id(s)述語関数、および 取得後に結果をストレージから削除するフラグ を使用できます。
Cancel(...)
まだ開始されていないタスクをキャンセルします。引数として work id(s) を使用できます。
PauseIfRequested()
タスクロジック内に一時停止ポイントを挿入します。
StopIfRequested(...)
タスクロジック内に停止ポイントを挿入します。引数として 停止処理前に実行する関数 を使用できます。
CheckIfRequestedStop()
タスクロジック内にチェックポイントを挿入し、Stop(...) が呼び出されたかを確認します。

サンプルコード

PowerPool powerPool = new PowerPool();

string id0 = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        powerPool.PauseIfRequested();
        if (powerPool.CheckIfRequestedStop())
        {
            return true;
        }
        // 何かを実行
    }
});
Task<ExecuteResult<bool>> resultTask = powerPool.FetchAsync<bool>(id0);
powerPool.Pause();
powerPool.Resume();
powerPool.Stop();
powerPool.Wait();
ExecuteResult<bool> result = await resultTask;

string id1 = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        powerPool.PauseIfRequested();
        powerPool.StopIfRequested();
        // 何かを実行
    }
});
powerPool.Pause(id1);
powerPool.Resume(id1);
powerPool.Stop(id1);
powerPool.Wait(id1);

詳細な説明

Pause(一時停止) | Resume(再開) | Stop(停止)

Thread.AbortThread.SuspendThread.Resume は予測不可能な動作を引き起こす可能性があり、新しい .NET バージョンでは非推奨になっています。そのため、PowerThreadPool ライブラリではこれらの API を使用してスレッドを制御しません。
PowerThreadPool は CancellationTokenSourceManualResetEvent の操作をカプセル化し、協調的なスレッドプールとタスク制御を提供します。

協調制御

タスクロジック内で PauseIfRequested()StopIfRequested(...)、または CheckIfRequestedStop()(例えば、ループや時間のかかるロジックのノード内)を挿入して、実行フローを管理できます。PauseResume、または Stop 関数を呼び出すと、ロジックが予期した位置で一時停止、再開、または停止します。これらの関数の引数としてタスク ID を使用することで、他のタスクが影響を受けないようにできます。

  • PauseIfRequested():タスクロジック内でこの関数を呼び出すと、Pause(...) が呼び出されたときにタスクがその場で一時停止します。
  • StopIfRequested(Func<bool> beforeStop = null):タスクロジック内でこの関数を呼び出すと、Stop(...) が呼び出されたときにタスクがその場で停止します。
    ロジックを終了するために、この関数は PowerThreadPool.Exceptions.WorkStopException をスローします。WorkStopException はタスクを停止するためだけに使用されるため、これをキャッチしないでください。PowerThreadPool が自動的に処理します。
    停止前にいくつかの操作(例えば、非管理リソースの解放)を実行したい場合、または特定の条件下で停止を防ぎたい場合は、引数 beforeStop を使用することをお勧めします。
    この方法でロジックを終了したくない場合は、CheckIfRequestedStop を使用することもできます。
  • CheckIfRequestedStop():タスクロジック内でこの関数を呼び出して、Stop(...) が呼び出されたかどうかを確認します。
    true を返す場合、いくつかの前処理操作(例えば、非管理リソースの解放)を実行した後、安全にロジックを終了できます。状況に応じて、停止要求を無視することも選択できます。
    この方法でタスクを停止すると、WorkStopped イベントはトリガーされず、タスクが正常に完了したと見なされます。
string workID = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        powerPool.PauseIfRequested();
        powerPool.StopIfRequested();
        // 何かを実行
    }
});
string workID = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        powerPool.PauseIfRequested();
        powerPool.StopIfRequested(() =>
        {
            // return 前に何かを実行
            if (/* 停止を続けたい場合 */)
            {
                return true;
            }
            else
            {
                return false;
            }
        });
        // 何かを実行
    }
});
string workID = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        if (powerPool.CheckIfRequestedStop())
        {
            // return 前に何かを実行
            return;
        }
        // 何かを実行
    }
});
powerPool.Pause();
powerPool.Pause(workID);
powerPool.Pause(workIDList);
powerPool.Resume();
powerPool.Resume(workID);
powerPool.Resume(workIDList);
powerPool.Stop();
powerPool.Stop(workID);
powerPool.Stop(workIDList);

強制停止

Stop 関数がブール引数(つまり forceStop)を true として受け取る場合、タスクロジック内に StopIfRequested(...) が挿入されていなくてもスレッドを停止できます。これは Thread.Interrupt() が呼び出されるためです。スレッドプールは ThreadInterruptedException をキャッチした後、スレッドを即座に終了します。
この方法は Thread.Abort よりも安全ですが、ビジネスロジックの観点からすると予測不可能な結果を引き起こす可能性があり、スレッドを終了するのに必要な時間を保証できません。そのため、強制停止は可能な限り避けるべきです
この方法で停止したスレッドは破棄され、再利用されません。

string workID = powerPool.QueueWorkItem(() =>
{
    while (true)
    {
        // 何かを実行
    }
});
powerPool.Stop(true);
powerPool.Stop(workID, true);
powerPool.Stop(workIDList, true);

Wait(待機)

呼び出しスレッドは、すべてのタスクが終了するまでブロックされます。
タスク ID を Wait の引数として使用することで、他のタスクが影響を受けないようにできます。
Wait の非同期バージョンは WaitAsync です。

powerPool.Wait();
powerPool.Wait(workID);
powerPool.Wait(workIDList);

Fetch(取得)

Fetch 関数はタスクの結果を取得するために使用されます。呼び出し後、タスクが完了次第 ExecuteResult を返します。

タスク ID を使用した結果の取得

workID または workIDList を引数として指定します。
通常、Fetch 関数はまだ開始されていない、または進行中のタスクの結果を取得するために使用されます。
この関数はブロッキング動作であり、指定されたタスクが完了して結果を返すまで、呼び出しスレッドの実行を一時停止します。
非ブロッキング動作を希望する場合は、FetchAsync 関数を使用できます。この関数はタスクの結果を非同期で取得し、呼び出しスレッドの実行を中断しません。

述語関数を使用した結果の取得

引数として 述語関数 を指定します。
述語関数を使用して、既存の結果から一致する結果セットを検索します。述語関数は、ExecuteResult<TResult> を引数として受け取り bool 値を返す関数であり、LINQ の Where に似ています。
既存の結果からフィルタリングするため、ブロッキングを引き起こさず、非同期バージョンはありません。

Fetch の非同期バージョンは FetchAsync です。

powerPool.Fetch(workID);
powerPool.Fetch(workIDList);
powerPool.Fetch<int>(x => x.Result >= 3);

完了したタスクの結果を取得

デフォルトでは、メモリオーバーフローを防ぐために、スレッドプールはタスクの実行結果を保存しません。完了したタスクの結果を保持したい場合は、WorkOption.ShouldStoreResulttrue に設定してください。これにより、タスクが完了した後に結果を保存するようスレッドプールに指示されます。

保存された実行結果のクリア

保存された実行結果をクリアする方法は以下の 3 つです:

  • PowerPoolOption.ClearResultStorageWhenPoolStarttrue に設定します。この設定により、スレッドプールが再実行状態に入るときに保存された実行結果がクリアされます。
PowerPool powerPool = new PowerPool(new PowerPoolOption() { ClearResultStorageWhenPoolStart = true });
  • Fetch 関数のオプション引数を true に設定します(Fetch(workID, true) など)。これにより、Fetch を呼び出したときにタスク ID に対応する実行結果がクリアされます。
powerPool.Fetch(workID, true);
powerPool.Fetch(workIDList, true);
  • PowerPool.ClearResultStorage(...) を直接呼び出します。
powerPool.ClearResultStorage();
powerPool.ClearResultStorage(workID);
powerPool.ClearResultStorage(workIDList);

Cancel(キャンセル)

Cancel 関数は、まだ開始されていないタスクをキャンセルするために使用されます。
タスク ID を Cancel の引数として使用することで、他のタスクが影響を受けないようにできます。

powerPool.Cancel();
powerPool.Cancel(workID);
powerPool.Cancel(workIDList);
Clone this wiki locally