2014-03-05 5 views
2

Не совсем уверен, что здесь происходит -TaskScheduler.FromCurrentSynchronizationContext исключение при вызове из рабочего потока

Этот бит кода вызывает проблемы, так как он первый из основной нити (проверено с точки зрения задач в VS) и планирование задачи, однако при установке точки останова в UpdateSearchCache мы сейчас в рабочем потоке - больше не основной!

Последующие фрагменты кода пользовательского интерфейса, вызываемые оттуда, не могут выполняться в рабочем потоке.

Разве это не все, что нужно для определения планировщика? Что мне не хватает?

Этот код вызывается при запуске нашего приложения. Он вызывается из Bootstrapper нашего приложения PRISM и работает на MainThread.

SynchronizationContext.Current не имеет значения, когда задача запущена.

var currentScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
var ctx = SynchronizationContext.Current; 
if (ctx == null) 
    throw new NullReferenceException(); 

Task.Factory 
    .StartNew(
     () => 
      SearchHelper.CacheSearchResults(_service.GetData()) 
    .ContinueWith(result => UpdateCache(result.Result), currentScheduler); 
+0

Выполняется ли первая строка фрагмента кода в основном потоке пользовательского интерфейса? Если да, выполняете ли вы это на 'Form.Load' и т. Д., Который находится внутри цикла ядра Application.Run? – Noseratio

+0

Да, это основной поток. – cacau

+2

Прежде чем сохранить его, сделайте следующее: 'Debug.Assert (SynchronizationContext.Current! = Null)'. Проходит ли это? – Noseratio

ответ

1

TaskScheduler.FromCurrentSynchronizationContext бросает InvalidOperationException, когда нет никакого контекста синхронизации на вызывающий поток т.е. SynchronizationContext.Current возвращает нуль.

+1

Но как этот метод выполняется в рабочем потоке, когда он должен работать в текущем потоке, a.k.a. main? – cacau

+0

@cacau - В какой последовательности запланировано продолжение, зависит от того, какой у вас контекст синхронизации. В контексте синхронизации по умолчанию запланированы задачи, которые должны выполняться в пуле потоков. Однако, если вы получаете исключение, проблема возникает до того, как вы даже начнете родительскую задачу, и здесь недостаточно кода, чтобы понять, почему это может произойти. – Lee

+0

Этот кусок звонка называется в нашем (PRISM) загрузчике прямо во время запуска нашего приложения. Вопрос отредактирован соответствующим образом. По крайней мере, в VS мы видим, что в то время существует куча рабочих потоков плюс основной поток. – cacau

1

Что-то действительно странное происходит здесь. Попробуйте следующий подход. Это обходное решение, но оно также может помочь в диагностике проблемы:

var dispatcher = Dispatcher.CurrentDispatcher; 
Debug.Assert(dispatcher == Application.Current.Dispatcher); 

Task.Factory 
    .StartNew(
     () => SearchHelper.CacheSearchResults(_service.GetData())) 
    .ContinueWith(result => 
    { 
     // is the app's dispatcher still the same? 

     Debug.Assert(dispatcher == Application.Current.Dispatcher); 

     // explicitly use Dispatcher.BeginInvoke, that's what 
     // DispatcherSynchronizationContext does behind the scene 

     Application.Current.Dispatcher.BeginInvoke(new Action(
      () => UpdateCache(result.Result))); 

    }, TaskContinuationOptions.ExecuteSynchronously); 
Смежные вопросы