2009-12-05 30 views
20

this SO questionを通過しましたが、役に立たなかったInvalidOperationException - オブジェクトが現在他の場所で使用されています

こちらのケースは異なります。私はバックグラウンドワーカーを使用しています。

algo1backgroundworker_DoWork() 
{ 
Image img = this.picturebox.Image; 
imgclone = img.clone(); 
//operate on imgclone and output it 
} 

algo2backgroundworker_DoWork() 
{ 
Image img = this.picturebox.Image; 
imgclone = img.clone(); 
//operate on imgclone and output it 
} 

同様の動作が他に行われる:第1のBackgroundWorkerは、私は、これがそれぞれのコードであり、他の3 backgroundworkers

algo1backgroundworker.RunWorkerAsync(); 
algo2backgroundworker.RunWorkerAsync(); 
algo3backgroundworker.RunWorkerAsync(); 

を呼び出す使用している)(ユーザの画像入力に及びfirstbackgroundworker_runworkercompleted内部動作を開始しますalgo * backgrougrondworker_doWork()。

私は "InvalidOperationException - オブジェクトは現在他の場所で使用されています"と表示しています。その非常に任意。私はいつもalgo1backgroundworker_DoWorkでalgo2backgroundworker_DoWorkで、時にはApplication.Run(new myWindowsForm())でこれを取得します。

私は何が起こっているのか分かりません。

答えて

39

GDI +には、2つのスレッドが同時にビットマップにアクセスできないようにするロックがあります。これはロックをブロックするものではなく、「プログラマが何か間違ったことをした、私は例外をスローします」という種類のロックです。すべてのスレッドでイメージをクローンしている(==ビットマップにアクセス中)ため、スレッドが爆発しています。あなたのUIスレッドは、スレッドがそれを複製しているときにビットマップ(==ビットマップにアクセスする)を描画しようとしているため、爆撃しています。

ビットマップへのアクセスを1つのスレッドに制限する必要があります。 BGWを起動する前にUIスレッドで画像を複製してください。各BGWには画像のコピーが必要です。 RunWorkerCompletedイベントのPBのImageプロパティを更新します。このようにいくつかの並行性は失われますが、それはやむを得ないことです。

19

したがって、BackgroundWorkersが同じWindowsフォームコンポーネントに同時にアクセスしようとしているようです。これはなぜ失敗がランダムであるのかを説明します。

あなたは、これはおそらくそうのように、lockを使用して起こらないことを確認する必要があります:私はimgcloneこのメソッドに対してローカルであることを確認してください

 private object lockObject = new object(); 

    algo1backgroundworker_DoWork() 
    { 
     Image imgclone; 
     lock (lockObject) 
     { 
     Image img = this.picturebox.Image; 
     imgclone = img.clone(); 
     } 
     //operate on imgclone and output it 
    } 

注 - あなたは間違いありませんすべての方法で共有したい!

一方、同じlockObjectインスタンスがすべてのメソッドで使用されます。 BackgroundWorkerメソッドがそのlock{}セクションに入ると、その時点まで来たものはブロックされます。したがって、ロックされたセクションのコードが高速であることを確認することが重要です。

処理された画像を出力するときは、UIに対するクロススレッドの更新を行わないように注意してください。 this postを調べれば、それを避けることができます。

1

Windowsフォームでは、1つのスレッドからコントロールにアクセスするだけでなく、そのスレッドがメインのアプリケーションスレッド、つまりコントロールを作成したスレッドである必要があります。

これは、DoWorkでは、(Control.Invokeを使用せずに)どのコントロールにもアクセスしないでください。ここでは、あなたのイメージクローンを渡すRunWorkerAsyncを呼び出します。 DoWorkイベントハンドラの内部では、DoWorkEventArgs.Argumentからパラメータを抽出できます。

ProgressChangedイベントハンドラとRunWorkerCompletedイベントハンドラのみがGUIと対話する必要があります。

関連する問題