2011-06-25 11 views
1

私は、あるスレッドで一連のイメージフィルタを通してイメージを処理し、別のスレッドのUIにイメージを表示するアプリケーションを持っています。簡略画像フィルタクラスは次のようになりますインデックスが範囲外ではないのに、コレクションにアクセスする際のArgumentOutOfRangeException?

// This class represents a filter operation on the GPU. 
// Process() is repeatedly called by the filter processing thread. 
class ShaderFilterBase : IFilter 
{ 
    // This variable holds the result of the image operation. 
    private ImageInfo resultImageInfo; 

    // Indicates whether the image has been updated by a call to Render() 
    bool hasChanged = true; 

    public ICollection<ImageInfo> LastResults 
    { 
     get 
     { 
      ICollection<ImageInfo> results = new Collection<ImageInfo>(); 
      results.Add(GetEffectResult()); 
      return results; 
     } 
    } 

    public ICollection<ImageInfo> Process(ICollection<ImageInfo> images) 
    { 
     // We only process the image if we have exactly one image. 
     // If more than one image has to be processed by the GPU, this method 
     // should be overridden in a derived class. 
     if (images.Count == 1) 
     { 
      ImageInfo firstImage = images.First(); 

      // If the supplied image is already a shader resource on the GPU, 
      // we don't need to upload the texture to the GPU again. We just 
      // set the output texture of the supplied image to the input texture 
      // of the current image. 
      if (firstImage.IsShaderResource) 
       SetResource(firstImage.ShaderResourceView); 
      else 
       UploadInputTexture(firstImage); 

      Render(); 

      firstImage.ShaderResourceView = OutputShaderResourceView; 
     } 

     return images; 
    } 

    public virtual void Render() 
    { 
     Monitor.Enter(this); 

     // Perform texture operations on the GPU    

     hasChanged = true; 

     Monitor.Exit(this); 
    } 

    public ImageInfo GetEffectResult() 
    { 
     Monitor.Enter(this); 

     if (hasChanged) 
     { 
      // Download image from GPU and store it in resultImageInfo 

      hasChanged = false; 
     } 

     Monitor.Exit(this); 

     return resultImageInfo; 
    } 
} 

はまた、Iは、HLSLシェーダプログラムによって異なる様々な派生クラスは、GPU上で実行されなければなりません。画像処理スレッドは、それらのフィルタインスタンスの集合を反復処理します。 GetEffectResult()は、イメージをビデオメモリからシステムメモリにダウンロードする必要がある場合にのみ呼び出されます。私はMonitor.Enter(this)を使用します。これは、各フィルターインスタンスがフィルターチェーン内に1回だけ存在することが保証されているためです。

フィルタを設定して設定するには、フィルタチェーン内のすべてのフィルタの出力を表示するUIがあります。フィルタインスタンスは、WPF UIによって消費されるフィルタモデルによってカプセル化されます。

internal abstract class FilterModelBase : DependencyObject 
{ 
    private WriteableBitmap preview; 

    private static readonly DependencyPropertyKey PreviewPropertyKey = DependencyProperty.RegisterReadOnly("Preview", 
     typeof(ImageSource), typeof(FilterModelBase), new PropertyMetadata()); 

    // The WPF window contains an Image control, which binds to this property. 
    public static readonly DependencyProperty PreviewProperty = PreviewPropertyKey.DependencyProperty; 

    public ImageSource Preview 
    { 
     get { return (ImageSource)GetValue(PreviewProperty); } 
     private set { SetValue(PreviewPropertyKey, value); } 
    } 

    // The underlying filter. 
    public IFilter Filter 
    { 
     get { return this.filter; } 
    } 

    protected FilterModelBase(IEventAggregator eventAggregator, IFilter filter) 
    { 
     Check.NotNull(filter, "filter"); 
     this.EventAggregator = eventAggregator; 

     this.filter = filter; 
    } 

    // Updates the filter output preview. 
    public virtual void Refresh(Dispatcher dispatcher) 
    { 
     if (!dispatcher.CheckAccess()) 
      dispatcher.Invoke(new Action(() => Refresh(dispatcher))); 
     else 
     { 
      ImageInfo filterImage = null; 

      Monitor.Enter(this.filter); 

      if (this.filter != null && this.filter.LastResults.Count > 0) 
       filterImage = this.filter.LastResults.ElementAtOrDefault(0); 

      if (filterImage != null) 
      { 
       this.preview.WritePixels(new Int32Rect(0, 0, filterImage.Width, filterImage.Height), 
        filterImage.ImageBytes, filterImage.Width * filterImage.Channels, 0); 
      } 

      Monitor.Exit(this.filter); 
     } 
    } 

各フィルタ・モデル・インスタンスのリフレッシュ()メソッドを繰り返しタイマを介してUIスレッドによって呼び出されます。

は毎日のようにして、私は次の行に例外ArgumentOutOfRangeExceptionを得る:私はLastResultsプロパティを検査する際

filterImage = this.filter.LastResults.ElementAtOrDefault(0); 

はしかし、それはちょうどそれが必要のように、一つの要素が含まれています。デバッガが実際にコレクションに正確に1つのアイテムを含み、常にコレクションの最初のアイテムにアクセスすると言っても、ArgumentOutOfRangeExceptionはどのように発生する可能性がありますか?

+0

挑発的なタイトルですが、私は例外を信じる傾向がありますが、あなたの足を引っ張るだけではなく、正しいです。アプリケーションはマルチスレッドですか? –

+0

いつも今度は==スレッディングレース。 –

+0

@Micheal:あなたはthis.filter.LastResultsを試しましたか?既に試してみたら、例外が発生した後で試してみてください。クイックランチウィンドウでコマンドを再実行して、プロパティが再作成されていないことを確認できますHTHのようにスローされた例外の後にデバッガによって評価されます。 –

答えて

3

の後に例外がスローされた後、プロパティはデバッガによって再評価されます。ビジュアルスタジオがデバッガのすべてを停止している間に、別のスレッドによって要素が挿入された可能性があります。

HTH

+0

ありがとう、私はデバッガがプロパティを再評価することを知らなかった。これは、おそらく、なぜ、ArgumentOutOfRange例外が発生する可能性がありますが、デバッガが数時間後にコレクションに項目があると言っても、タイトルに記載された質問を説明します。 LastResultsによって返されたコレクションにアイテムが含まれていないことはまだ分かりません(プロパティの定義を見ると、プロパティが呼び出されるたびにコレクションにアイテムが無条件に追加されます)。 – Michael

関連する問題