Ich habe einen Bibliothekscode (Socket Networking), der eine Task
API auf der Basis von ausstehenden Antworten auf Anforderungen basierend auf bereitstellt TaskCompletionSource<T>
. Es ist jedoch ärgerlich in der TPL, dass es unmöglich zu sein scheint, synchrone Fortsetzungen zu verhindern. Was würde ich gerne der Lage sein zu tun , entweder:
- Sagen Sie einem,
TaskCompletionSource<T>
dass es Anrufern nicht gestattet sein sollte, sich mitTaskContinuationOptions.ExecuteSynchronously
oder zu verbinden - Stellen Sie das Ergebnis (
SetResult
/TrySetResult
) so ein, dass angegeben wird, dassTaskContinuationOptions.ExecuteSynchronously
es ignoriert werden soll, und verwenden Sie stattdessen den Pool
Insbesondere habe ich das Problem, dass die eingehenden Daten von einem dedizierten Lesegerät verarbeitet werden und wenn ein Anrufer eine Verbindung herstellen kann TaskContinuationOptions.ExecuteSynchronously
, kann er das Lesegerät blockieren (was mehr als nur sie betrifft). Früher habe ich um diese von einigen Hacks gearbeitet, der erkennt , ob irgendwelche Fortsetzungen vorhanden sind, und wenn sie drückt er den Abschluss auf die ThreadPool
jedoch hat dies erhebliche Auswirkungen , wenn der Anrufer seine Arbeit Warteschlange gesättigt ist, da der Abschluss nicht bearbeitet erhalten rechtzeitig. Wenn sie Task.Wait()
(oder ähnliches) verwenden, blockieren sie sich im Wesentlichen selbst. Aus diesem Grund befindet sich der Leser in einem dedizierten Thread, anstatt Worker zu verwenden.
Damit; Bevor ich versuche, das TPL-Team zu nerven: Fehlt mir eine Option?
Wichtige Punkte:
- Ich möchte nicht, dass externe Anrufer meinen Thread entführen können
- Ich kann das nicht
ThreadPool
als Implementierung verwenden, da es funktionieren muss, wenn der Pool gesättigt ist
Das folgende Beispiel erzeugt eine Ausgabe (die Reihenfolge kann je nach Timing variieren):
Continuation on: Main thread
Press [return]
Continuation on: Thread pool
Das Problem ist die Tatsache, dass es einem zufälligen Anrufer gelungen ist, eine Fortsetzung des "Hauptthreads" zu erhalten. Im realen Code würde dies den primären Leser unterbrechen; schlechte Dinge!
Code:
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
mit meiner eigenen API zu verpacken , um einen direkten Aufruf von zu verhindernContinueWith
, da wederTaskCompletionSource
nochTask
gut für die Vererbung von ihnen geeignet ist.