Как я могу предотвратить синхронное продолжение задания?
У меня есть некоторый код библиотеки (сокет сети), который обеспечивает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();
}
}