Поскольку ваша задача продолжения (через ContinueWith
) задает TaskScheduler
, TPL использует ее для всех других задач, запускаемых далее вниз по стеку вызовов, независимо от того, указали ли вы их на самом деле. Другими словами, вызовы Task.Factory.StartNew
, исходящие от делегата Action
, указанного в ContinueWith
, будут автоматически использовать указанный TaskScheduler
по умолчанию.
Я изменил ваш код, чтобы помочь вам лучше визуализировать происходящее.
private void BeginOperation()
{
System.Diagnostics.Trace.WriteLine("BeginOperation-top " + Thread.CurrentThread.ManagedThreadId);
var context = TaskScheduler.FromCurrentSynchronizationContext();
Task task = Task.Factory.StartNew(() =>
{
System.Diagnostics.Trace.WriteLine(" BeginOperation-StartNew-top " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(5000);
System.Diagnostics.Trace.WriteLine(" BeginOperation-StartNew-bottom " + Thread.CurrentThread.ManagedThreadId);
}, TaskCreationOptions.LongRunning)
.ContinueWith(_ =>
{
System.Diagnostics.Trace.WriteLine(" BeginOperation-ContinueWith-top " + Thread.CurrentThread.ManagedThreadId);
EndOperation();
System.Diagnostics.Trace.WriteLine(" BeginOperation-ContinueWith-bottom " + Thread.CurrentThread.ManagedThreadId);
}, context);
System.Diagnostics.Trace.WriteLine("BeginOperation-bottom " + Thread.CurrentThread.ManagedThreadId);
}
private void EndOperation()
{
System.Diagnostics.Trace.WriteLine("EndOperation-top " + Thread.CurrentThread.ManagedThreadId);
BeginOperation();
System.Diagnostics.Trace.WriteLine("EndOperation-bottom " + Thread.CurrentThread.ManagedThreadId);
}
Я проверил код в ContinueWith
с помощью Reflector и могу подтвердить, что он пытается обнаружить контекст выполнения, используемый вызывающей стороной. Да, верьте или нет, и, несмотря на вашу естественную интуицию, это именно то, что он делает.
Лучшим решением, вероятно, было бы иметь выделенный поток для аппаратного опроса.