2016-09-04 2 views
-1

私はクライアントC#アプリケーションの1つにこの非常に奇妙なことがあります。 SharpDXを使用してMedia Foundationを使用するWPFアプリケーションです。目的は、所定のプレイリストを使用して広告を再生することである。 SharpDXコンポーネントは、WPFのUIスレッドと並んで、独自のスレッドで実行されている別のライブラリで抽象化されています。これはとてもうまくいきます!Task.Runとデッドロックが発生しましたか?

SharpDX実装の一部は、再生リストが指示どおりに再生されるようにする再生リストスケジューラです。 15秒のビデオは本当に15秒間再生する必要があります。

以前は、スケジューラをオンデマンドで開始/停止できるように、私はThreadManualResetEventを使用していました。一度に1つのスケジューラしか実行しないので、この作業は不思議です。

しかし、要件が変更され、複数のプレイリストを同時に再生する必要があります。つまり複数のスケジューラも同時に再生する必要があります。まもなく私は不明な理由でデッドロックに気付きはじめ、TaskCancelationTokenの方法に「アップグレードする」と考えました。ここで

は、それが今どのように動作するかの抜粋です:

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を使用して開始された実行している2つのスケジューラを持っている、と私はDestroyScheduleThreadを使用して、他の後にそれらの両方でキャンセルすると、2回目の呼び出しは時折_task.Wait()ラインにハングアップします。私はなぜそれがそれを行うかを世界が理解することはできません...私はそれを確実に引き起こすことはできません。

デバッグ時に、ScheduleThread -loopは実行されていないため、タスクは完了しています。しかし、_taskを調べると、まだ実行中だと主張しています。

質問:なぜこれが起こるのか、そして最も重要なのは誰ですか?どのように修正するのですか?

+1

GUIスレッドから '_task.Wait()'を呼び出すべきではありません。だから私はあなたがたどったインターネットの例を疑問に思います。 –

+0

ConfigureAwaitf(false)を使用してテストしましたか? –

+0

私は仕事についてmcuhは分かりませんが、あなたはすべての仕事に同じcancelationTokenを使用していませんか? – null

答えて

0

私はメソッドを非同期にし、Task.Waitの代わりに、私は少なくとも私の場合はuiをブロックすることはありません。だから "待つタスク"を試して、メソッドを非同期にしておくとよいでしょう。

+0

あなたは '非同期void'メソッドを持っていますか? 'async void'の一般的なアドバイスは、あなたがイベントを扱っていない限りDo notです。非同期になると、Stephen ClearyやStephen Taubの何かが優れています。 https://msdn.microsoft.com/en-us/magazine/jj991977.aspx?f=255&MSPPError=-2147217396 – stevieg

+0

'async void'は、イベントハンドラのためにはOKです。しかし、try/catchでボディをラップします。 –

関連する問題