2016-09-04 4 views
-1

Итак, у меня есть эта очень странная вещь в одном из приложений C# для клиентов. Это приложение WPF, использующее Media Foundation с помощью SharpDX. Цель состоит в том, чтобы воспроизводить рекламу с использованием заранее определенного списка воспроизведения. Компонент SharpDX абстрагируется в отдельной библиотеке, запущенной в собственном потоке, наряду с потоком пользовательского интерфейса WPF. Это работает очень хорошо!Task.Run и Wait deadlocking?

Часть реализации SharpDX - это планировщик плейлистов, который обеспечивает воспроизведение плейлиста в соответствии с инструкциями. Видео за 15 секунд ДЕЙСТВИТЕЛЬНО должно играть в течение 15 секунд.

В прошлом я использовал Thread и ManualResetEvent, чтобы иметь возможность запускать/останавливать планировщик по требованию. За один раз будет запускаться только один планировщик, поэтому эта работа задается вопросом.

Однако требования изменились, и теперь нам нужно одновременно воспроизводить несколько плейлистов, что также означает несколько планировщиков. Вскоре я начал замечать тупики по неизвестным причинам и решил, что просто «обновить» до Task и CancelationToken.

Вот фрагмент того, как она работает прямо сейчас:

private void CreateScheduleThread() 
    { 
     DestroyScheduleThread(); 

     _cancellationTokenSource = new CancellationTokenSource(); 

     CancellationToken cancellationToken = _cancellationTokenSource.Token; 

     _task = Task.Run(
      () => ScheduleThread(cancellationToken), 
      cancellationToken 
      ); 
    } 

    private void DestroyScheduleThread() 
    { 
     if (_cancellationTokenSource != null) 
     { 
      _cancellationTokenSource.Cancel(); 

      try 
      { 
       _task.Wait(); 
      } 
      catch 
      { 
       //Do nothing 
      } 

      _cancellationTokenSource.Dispose(); 
      _cancellationTokenSource = null; 
     } 
    } 

    private void ScheduleThread(CancellationToken cancellationToken) 
    { 
     while (true) 
     { 
      cancellationToken.ThrowIfCancellationRequested(); 

      //Do more stuff 
     } 
    } 

По мнению большинства интернет-примеров, это правильный способ установки отменяемой задачи. Когда мы создаем новый планировщик, мы должны убедиться, что предыдущий (в том же экземпляре класса, в котором он живет) разрушен, прежде чем продолжить. В этом когда возникает проблема.

Проблема: Когда у меня есть два планировщиков под управлением которых начали использовать CreateScheduleThread, и я отменить их обоих на за другой, используя DestroyScheduleThread, второй вызов будет иногда висеть на _task.Wait() линии. Я не могу понять, почему он это делает ... и я не могу уверенно вызвать его.

При отладке ScheduleThread -loop больше не работает, поэтому задача завершена. Однако при проверке _task он утверждает, что он все еще работает.

Вопрос: У кого-нибудь есть ключ к тому, почему это происходит и что самое главное, как его исправить?

+1

Вы не должны вызывать '_task.Wait()' из потока графического интерфейса. Поэтому мне интересно, какие интернет-примеры вы следовали. –

+0

Пробовали ли вы использовать ConfigureAwaitf (false)? –

+0

Я не знаю mcuh о задачах, но вы не используете то же самое cancelationToken для всех задач правильно? – null

ответ

0

Я узнал, что если я сделаю метод асинхронным и вместо Task.Wait, я использую задачу wait, он никогда не блокирует ui, по крайней мере, в моем случае. Поэтому попробуйте «ожидание задачи» и отметьте метод async, тогда он должен быть лучше.

+0

У вас есть метод async void? Общий совет для 'async void' - Do not, если вы не имеете дело с событиями. Когда дело доходит до асинхронного действия Стивена Клири или Стивена Тауба, это отлично. https://msdn.microsoft.com/en-us/magazine/jj991977.aspx?f=255&MSPPError=-2147217396 – stevieg

+0

'async void' в порядке (предназначен для) обработчиков событий. Но заверните тело в попытку/уловку. –

Смежные вопросы