にTask
基づいて、リクエストへの保留中の応答にベースのAPIを提供するライブラリ(ソケットネットワーク)コードがありますTaskCompletionSource<T>
。ただし、同期継続を防ぐことは不可能であるように思われるという点で、TPLには煩わしさがあります。私はなりたいと行うことができるようにすることのいずれかです:
TaskCompletionSource<T>
発信者が、、TaskContinuationOptions.ExecuteSynchronously
またはで接続することを許可してはならないことを伝えます- 代わりにプールを使用して、無視する必要があることを指定する方法で結果(
SetResult
/TrySetResult
)を設定しTaskContinuationOptions.ExecuteSynchronously
ます
具体的には、私が抱えている問題は、受信データが専用のリーダーによって処理されており、発信者が接続できる場合TaskContinuationOptions.ExecuteSynchronously
、リーダーをストールさせる可能性があることです(これはそれらだけに影響を与えるだけではありません)。以前、私はかどうかを検出することをいくつかの牛車でこれを回避働いている任意の継続が存在し、それらがある場合、それはへの完了を押してThreadPool
完了が処理されませうとして、発信者が、自分の仕事のキューを飽和している場合は、しかし、これは重大な影響を持っていますタイムリーに。彼らが使用しているTask.Wait()
(または同様の)場合、彼らは本質的に彼ら自身をデッドロックさせます。同様に、これが、リーダーがワーカーを使用するのではなく、専用のスレッドを使用している理由です。
そう; TPLチームを悩ませる前に:オプションがありませんか?
キーポイント:
- 外部の発信者が自分のスレッドを乗っ取れるようにしたくない
ThreadPool
プールが飽和状態のときに機能する必要があるため、実装として使用することはできません
以下の例では、出力が生成されます(順序はタイミングによって異なる場合があります)。
Continuation on: Main thread
Press [return]
Continuation on: Thread pool
問題は、ランダムな呼び出し元が「メインスレッド」で継続を取得できたという事実です。実際のコードでは、これはプライマリリーダーを中断します。悪いこと!
コード:
using System;
using System.Threading;
using System.Threading.Tasks;
static class Program
{
static void Identify()
{
var thread = Thread.CurrentThread;
string name = thread.IsThreadPoolThread
? "Thread pool" : thread.Name;
if (string.IsNullOrEmpty(name))
name = "#" + thread.ManagedThreadId;
Console.WriteLine("Continuation on: " + name);
}
static void Main()
{
Thread.CurrentThread.Name = "Main thread";
var source = new TaskCompletionSource<int>();
var task = source.Task;
task.ContinueWith(delegate {
Identify();
});
task.ContinueWith(delegate {
Identify();
}, TaskContinuationOptions.ExecuteSynchronously);
source.TrySetResult(123);
Console.WriteLine("Press [return]");
Console.ReadLine();
}
}
TaskCompletionSource
直接呼び出さないように、独自のAPIでラップしようとしますContinueWith
。これはTaskCompletionSource
、が、またはTask
それらからの継承に適していないためです。