4

私は現在 Fractal Explorer プログラムを書いていますが、本当に奇妙な問題に遭遇しています: BufferedImage にフラクタルを描画していて、その画像にランダムな黒い領域が表示されます。スクリーンショット: http://imgur.com/a/WalM7

イメージはマルチスレッドで計算されます: 大きなイメージは 4 つのサブイメージに分割され (4 コア プロセッサを使用しているため)、個別に計算されます。黒い領域は、各サブイメージの先頭に表示されます。それらは常に長方形であり、必ずしもピクセルが計算される順序に従っているとは限りません (左から右ですが、領域は常にサブイメージの向こう側に伸びるとは限りません)。

ピクセルが (Graphics.drawLine を使用して) 描画された直後に、BufferedImage.getRGB がピクセルの正しい色を返すことを確認しましたが、計算が終了すると、ピクセルが画面に描画されるため、代わりに黒が返される場合があります。

マルチスレッド計算を無効にすると (タスク マネージャーを介して javaw.exe に 1 つのコアのみを割り当てることにより)、問題は解消されるようですが、マルチコア計算を放棄する必要はありません。他の誰かがこの問題に遭遇しましたか (Google と stackoverflow で何も見つかりませんでした)、それを修正する方法を知っていますか?

Graphics.drawLine 呼び出しは、Graphics オブジェクトで同期されます。さらに BufferedImage で同期しても、何も変わりません。

バグを自分で確認したい場合は、http://code.lucaswerkmeister.de/jfractalizer/でプログラムをダウンロードできます。GitHub (https://github.com/lucaswerkmeister/JFractalizer) でも利用できますが、最近 GitHub に切り替えたばかりで、最初の GitHub コミットで問題がすでに明らかになっています。

4

2 に答える 2

3

問題は、BufferedImage も Graphics もスレッドセーフではなく、計算後に BufferedImage を読み取るスレッドに古い値が表示されることだと思います。

あなたが言ったように BufferedImage で同期すると、実際に役立つはずです。ただし、読み取り専用アクセスを含む、すべてのスレッドからのすべてのアクセスを同期する必要があることに注意してください。したがって、私の推測では、あるコンポーネント (AWT スレッドである必要があります) で BufferedImage を描画するスレッドは、同期せずに描画するため、古い値が表示されます。

ただし、複数のスレッド間で BufferedImage を共有する代わりに、各スレッドに個別の画像を与えて描画できるようにすることをお勧めします。次に、すべてのスレッドが終了したら、それらの作業を AWT スレッドの新しいイメージに結合します。

また、まだExecutorServiceを使用していない場合は、それを使用することをお勧めします。Callableタスク (この場合はワーカー スレッドのイメージ部分)の戻り値の可視性の問題がライブラリ クラスによって処理されるという利点があります。

これら 2 つの方法を組み合わせると、手動で同期を行う必要がなくなります。これは常に良いことです (間違えやすいため)。

于 2012-10-03T12:47:08.883 に答える
0

データがグラフィックス カード上に存在する可能性があるため、バッファリングされたイメージはスレッド セーフではない場合があります。ただし、これはオーバーライドできます。((DataBufferInt) image.getRaster().getDataBuffer()).getData()画像全体を高速に描画するための秘密のテクニック (選択した画像の種類によってデータ バッファーの種類が異なります) を使用すると、高速化されていない画像が得られます。同じピクセルに 2 回書き込むことがない限り、これは理論的には完全に安全です。ただし、画像からピクセルを読み取る前に、何らかの方法でスレッドを join() することを忘れないでください。スレッドの死を必要とするため、スレッドからの join() メソッドは実際には推奨されません。

関連メモ: あなたが目撃しているちらつきは、おそらく awt が画面にレンダリングする方法のアーティファクトです。即時モードで実行されます。つまり、実行するすべての描画アクションで画面がすぐに更新されます。これにより、複数のオブジェクトをウィンドウに直接レンダリングする速度が低下します。ダブルバッファリング戦略を実装することで、ちらつきを回避できます。私は中間イメージに描画してから、そのイメージのみを画面に描画するのが好きです。

于 2012-12-14T22:21:55.760 に答える