0

私はまだ.net 4.5のスレッドモデル(または一般的なスレッド)にかなり慣れていません。一連の同様のタスクをマルチスレッド化するためのフレームワークを実装するために、一連の抽象クラスを構築しようとしています。ルールは、入力の最初の行がセット内の問題の数を示し、次の行に各問題の入力が含まれていることです。セットを構成する入力の行数は、タスクごとに異なる場合がありますが、通常、特定の種類の問題では一貫しています。各問題は、出力として 1 行のテキストを持つことです。

目標は、これらのクラスから継承できるようにすることであり、CreateWorker メソッドと DoWork メソッドの実装についてのみ心配する必要があります。UI は ProcessInput を呼び出して処理を開始し、WriteOutput を呼び出して結果を一覧表示します。

私がこれまでに持っている基本的なテンプレートは次のとおりです。

public abstract class Wrapper
{
    protected int N;
    protected WorkerBase[] ProblemSet;
    protected List<Task> Tasks;

    public virtual void ProcessInput(TextReader input)
    {
        string Line = input.ReadLine();
        N = int.Parse(Line);
        ProblemSet = new WorkerBase[N];
        Tasks= new List<Task>(N);
        for (int index = 0; index < N; index++)
        {
            WorkerBase T = CreateWorker(input);
            Tasks.Add(T.DoWorkAsync());
            ProblemSet[index] = T;
        }
    }

    public virtual bool WriteOutput(TextWriter outputStream, int timeout)
    {
        bool Complete = Task.WaitAll(Tasks.ToArray(), timeout);

        for (int index = 0; index < N; index++)
        {
            outputStream.WriteLine(ProblemSet[index].Result);
        }

        return Complete;
    }

    protected abstract WorkerBase CreateWorker(TextReader inputStream);
    protected abstract class WorkerBase
    {
        public string Result
        {
            get;
            protected set;
        }
        protected abstract void DoWork();
        public Task DoWorkAsync()
        {
            return Task.Run(() => DoWork());
        }
    }
} 

現状では、これは私の要件を満たしています。しかし今、すべてのスレッドを停止できるアボート機能を Wrapper クラスに追加したいと考えています。問題は、キャンセル ボタンがクリックされた場合に UI がプロセスを中止できるように、中止機能をこの構造に組み込むにはどうすればよいかということです。できれば、DoWork 実装で余分なコードを記述する必要はありません。

タスクを中止するためにキャンセル トークンを渡すパターンを見つけましたが、見つかったすべてのバージョンで、DoWork がトークンの状態をチェックし、それ自体を中止する必要があります。メソッドの外部から DoWork を中止する方法が本当に必要です。

4

1 に答える 1

2

実行中のコードの中止は 2 つの方法で行うことができます (まあ、「やるべきことのキューから開始されない」を含めると、ちょっと 3 です。これは、キャンセルされたタスクで既に発生していると思われます)、そのうちの 1 つだけが正気です:

  • 作業は定期的に「中止」フラグをチェックし、正常に終了します
  • スレッド全体を中止します

1 つ目は、何をすべきかです。ほとんどの場合、問題なく動作します。2 つ目は、事実上決して良い考えではありません。これを考慮する必要があるのは、プロセス全体が非常に末期的であり、できるだけ早くそれを停止したい (そして悲惨な状態から抜け出したい) 場合だけです。スレッドを中止した後、システムを回復不能な状態に置いたままにしておく可能性は十分にあるため、これはほとんどの正常な操作には使用しないでください。また、関連するそれぞれへの参照が必要ですがThread、ここにはありません。

つまり、最初のケースを残します。率直に言って、ここでフラグを取得して確認する必要があると思います。ただし、ワーカーが定期的にどこかから値を取得する必要がある場合にうまく機能する別のアプローチは、すべての入力プロパティ/メソッド/その他にそこでチェックを実行させ、既知の例外を発生させることです。つまり、ワーカーが例外を受け取る可能性がありますアクセスしているときfoo.Count(または同様のもの)。

ただし、タスクのステータスを維持できるように、キャンセルを正式に確認し、キャンセルしたことを報告することをお勧めします。catchただし、ブロックからこれを行うこともできると思います。

于 2013-05-04T15:09:59.487 に答える