У мене є якийсь бібліотечний (мережевий) код, який надає Task
API на основі очікуваних відповідей на запити на основі TaskCompletionSource<T>
. Однак у TPL є роздратування, оскільки, здається, неможливо запобігти синхронним продовженням. Що б я хотів , щоб бути в змозі зробити це або:
- скажіть a,
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
інше не підходить для успадкування від них.