1

すべて、タスクパラレルライブラリ(TPL)を使用してバックグラウンドスレッド(キャンセルサポート付き)で実行する長時間実行プロセスがあります。この長時間実行されるタックのコードはClass Validation、メソッド内に含まれています。

public bool AsyncRunValidationProcess(TaskScheduler _uiScheduler, 
    CancellationToken _token, dynamic _dynamic = null)
{
    try
    {

        // Note: _uiScheduler is used to update the UI thread with progress infor etc.

        for (int i = 0; i < someLargeLoopNumber; i++)
        {
            // Cancellation requested from UI Thread.
            if (_token.IsCancellationRequested) 
                _token.ThrowIfCancellationRequested();
        }
        return true;
    }
    catch (Exception eX)
    {
        // Do stuff. Display `eX` if cancellation requested.
        return false;
    }
}

から実行されますClass Validation私はプロセスを正常にキャンセルすることができます。キャンセルリクエストは適切なものdelegate(以下に表示)によって処理され、これは正常に機能します(これが私の問題の原因であるとは思わない)。

このメソッドを別のクラスから実行する場合Class Batch、「コントローラー」メソッドを介してこれを実行します

asyncTask = Task.Factory.StartNew<bool>(() => asyncControlMethod(), token);

次にメソッドを呼び出します

valForm.AsyncRunValidationProcess(uiScheduler, token, 
    new List<string>() { strCurrentSiteRelPath }));

valFormへのアクセサはどこにありますかClass Validation、メソッドは正常に実行されますが、キャンセルを試みると、delegate

cancelHandler = delegate 
{
    UtilsTPL.CancelRunningProcess(asyncTask, cancelSource);
};

どこ

public static void CancelRunningProcess(Task _task, 
    CancellationTokenSource _cancelSource)
{
    try
    {
        _cancelSource.Cancel();
        _task.Wait(); // On cross-class call it freezes here.
    }
    catch (AggregateException aggEx)
    {
        if (aggEx.InnerException is OperationCanceledException)
            Utils.InfoMsg("Operation cancelled at users request.");
        if (aggEx.InnerException is SqlException)
            Utils.ErrMsg(aggEx.Message);
    }
}

でフリーズ/ハングします(未処理の例外などはありません)_task.Wait()。これ(私は信じています-テストを通して)は、私がキャンセルしているという事実と関係があります。これは、asyncControlMethod()を呼び出しvalForm.AsyncRunValidationProcess(...)たのでasyncControlMethod()、現在のプロセスがハングする原因となっているキャンセルです。CancellationTokenSource問題は、子メソッドに渡すなどにあるようです。イベントが発生して制御メソッドが強制終了されIsCancellationPending、子メソッドがハングします。

誰かが私が間違っていることを教えてもらえますか、または(より適切には)そのようなキャンセル手続きを許可するために私は何をすべきですか?

注:子タスクを生成して実行しようとしvalForm.AsyncRunValidationProcess(...)ましCancellationTokenたが、これは機能しませんでした。

御時間ありがとうございます。

4

1 に答える 1

0

この問題への答え(Jiaji Wuのコメントとリンクによって大いに助けられました)はCancellationToken、カスケードメソッドに渡されるグローバル変数としてを宣言できないということでした。つまり、あなたは持つことはできません

public class MainClass
{
    private CancellationTokenSource = source;
    private CancellationToken token;

    public MainClass()
    {
        source = new CancellationtokenSource();
        token = source.Token;
    }

    private void buttonProcessSel_Click(object sender, EventArgs e)
    {
        // Spin-off MyMethod on background thread.
        Task<bool> asyncControllerTask = null;
        TaskSpin(asyncControllerTask, cancelSource, token, MyMethod);
    }

    private void method()
    {
        // Use the global token DOES NOT work!
        if (token.IsCancellationRequested)      
            token.ThrowIfCancellationRequested();
    }

    private void TaskSpin(Task<bool> asyncTask, CancellationTokenSource cancelSource,
        CancellationToken token, Func<bool> asyncMethod)
    {
        try
        {
            token = cancelSource.Token;
            asyncTask = Task.Factory.StartNew<bool>(() => asyncMethod(token), token);

            // To facilitate multitasking the cancelTask ToolStripButton
            EventHandler cancelHandler = null;
            if (cancelSource != null)
            {
                cancelHandler = delegate
                {
                    UtilsTPL.CancelRunningProcess(mainForm, uiScheduler, asyncTask, cancelSource, true);
                };
            }

        // Callback for finish/cancellation.
            asyncTask.ContinueWith(task =>
            {
                // Handle cancellation etc.
            }

            // Other stuff...
        }
    }
}

バックグラウンドスレッドで実行されるmaethodでのグローバルトークンの使用は機能しません!tokenメソッドを登録できるようにするには、メソッドを明示的に渡す必要があります。これが当てはまる正確な理由はわかりませんが、将来的にはわかります。MyMethod()これを気に入ってもらうには、トークンを渡す必要があります。

    private void method(CancellationToken token)
    {
        // Use the global token DOES NOT work!
        if (token.IsCancellationRequested)      
            token.ThrowIfCancellationRequested();
    }

これが他の誰かに役立つことを願っています。

于 2012-05-18T10:44:29.123 に答える