6

Task Parallel Libraryの使用を開始したいと思います。これは、非同期操作を実行するために今後推奨されるフレームワークです。私が見つけることができなかったものの 1 つは、Thread.Abort が提供するものなど、強制的な中止の手段です。

私が特に懸念しているのは、完全に信頼したくないコードを実行するタスクをスケジュールすることです。特に、この信頼できないコードがデッドロックしないと確信できないため、このコードを使用してスケジュールしたタスクが完了するかどうか確信が持てません。(マーシャリングのオーバーヘッドと複雑さのため) 真の AppDomain 分離から離れたいと思っていますが、Task スレッドをデッドロックしたままにしたくありません。TPLでこれを行う方法はありますか?

4

3 に答える 3

9

これを行う方法は、CancellationToken と新しいキャンセル モデルを使用することです。新しいキャンセル モデルは、いくつかの種類で .NET Framework に統合されています。最も重要なものは、System.Threading.Tasks、System.Threading.Tasks.Task、System.Threading.Tasks.Task、および System.Linq.ParallelEnumerable です。

これがあなたの問題の例です。呼び出し元のコードが最初にロックを取得し、次にデッドロックされたタスクが同じロックを取得しようとするため、このコードは常にデッドロックします。

public void Example()
{
    object sync = new Object();
    lock (sync)
    {
        CancellationTokenSource canceller = new CancellationTokenSource();
    ManualResetEvent started = new ManualResetEvent(false);
        Task deadlocked = Task.Factory.StartNew(() => 
            { 
            started.Set();
                // EVIL CODE: This will ALWAYS deadlock
                lock(sync) { }; 
            }, 
            canceller.Token);

        // Make sure task has started.
    started.WaitOne(); 

        canceller.Cancel();

        try
        {
            // Wait for task to cancel.
            deadlocked.Wait();
        }
        catch (AggregateException ex) 
        {
            // Ignore canceled exception. SIMPLIFIED!
            if (!(ex.InnerException is TaskCanceledException))
                throw;
        }
    }
}

TPL でのタスクのキャンセルは協調的です。つまり、タスク スレッドがロックされているためにキャンセルに設定されているキャンセル トークンが処理されないため、これは常にデッドロックになります。

これを回避する方法はありますが、信頼できないコードの作成者が正しいことを行うことに依存しています。

public static void Example2()
{
    Mutex sync = new Mutex(true);

    CancellationTokenSource canceller = new CancellationTokenSource();
    bool started = false;

    Task deadlocked = Task.Factory.StartNew(() =>
        {
            started = true;
            // EVIL CODE: This will ALWAYS deadlock 
            WaitHandle.WaitAny(new WaitHandle[] { canceller.Token.WaitHandle, sync });
        },
        canceller.Token);

    // Make sure task has started.
    while (!started) { }

    canceller.Cancel();

    try
    {
        // Wait for task to cancel. 
        deadlocked.Wait();
    }
    catch (AggregateException ex)
    {
        // Ignore canceled exception. SIMPLIFIED! 
        if (!(ex.InnerException is TaskCanceledException))
            throw;
    }
} 

注意点; キャンセルは協力的です。Token.WaitHandle を使用してハンドルを取得し、他の同期プリミティブのハンドルと共に待機できます。Mutex は、Monitor (またはロック) よりもはるかに低速です。

実際、コードの作成者に協調的なキャンセルを実装させるほど信頼していない場合は、同じスレッドの AppDomain 内でそれらを実行することの正気を疑うでしょう。

詳細については、以下を参照してください。

http://msdn.microsoft.com/en-us/library/dd997364.aspx

http://msdn.microsoft.com/en-us/library/dd537607.aspx

http://msdn.microsoft.com/en-us/library/ee191552.aspx

于 2010-05-06T06:43:16.830 に答える
0

Dan Task.Wait(timeout) がこのタスクをキャンセルするとは思わない.Overload Task.Wait(timeout,cancelationToken) があるが、トークンが通知されたときに task.Wait で OperationCanceledException をスローするだけだ。

Task.Wait は、タスクが完了するかタイムアウトになるまでブロックするだけで、タスク自体をキャンセルまたは中止することはありません。そのため、デッドロックされたタスクは ThreadPool でハングしたままになります。未完了のタスク (InvalidOperation) を破棄することはできません。

私はあなたと同じ種類のアプリケーションを書いています.Abortingを許可する独自のtaskSchedulerを作成しました(そしてthreadpool :(を使用していません)。

しかし、あなたがこの問題をどのように解決したかについては非常に興味があります。私に応答してください。

于 2010-05-03T16:18:34.143 に答える
-4

を呼び出すだけTask.Wait(timespanToWait)です。

指定された期間が経過してもタスクが完了しない場合、タスクはキャンセルされます。

于 2010-04-23T01:33:53.980 に答える