数時間のデバッグと分析の結果、私は最終的に競合状態の原因を切り分けることができました。それを解決することは別の問題です!Java AWT drawImage競合条件 - 同期を使用して回避する方法
動作中の競合状態を確認するために、何らかの方法でデバッグプロセスにビデオを記録しました。それ以来私はその状況を理解していたので、デバッギングプロセスの一環として実装された貧弱な解説と愚かなメカニズムを許してください。だから、
http://screencast.com/t/aTAk1NOVanjR
、状況:我々は、レンダリングプロセスを(起動、ダブルバッファリング表面の実装、本質的に連続してループする継続的なスレッドがある(すなわちするjava.awt.Frameまたはウィンドウ)を持っていますUIレイアウトを実行してバックバッファにレンダリングします)、レンダリング後の領域をバックバッファからスクリーンにブリットします。 - それにも実装(AWT.javaでライン507、
public RenderedRegions render() {
// pseudo code
RenderedRegions r = super.render();
if (r==null) // nothing rendered
return
for (region in r)
establish max bounds
blit(max bounds)
return r;
}
任意AWT表面実装と同じように:ここ
レンダリングダブルバッファの擬似コードのバージョン(フルバージョン線Surface.javaの824)ですリンク制限:( - また、画面にバックバッファからブリット塗料/更新オーバーライド)PLAT/AWT.javaとコア/ Surface.javaを交換し、Surface.javaリンクを使用:
public void paint(Graphics gr) {
Rectangle r = gr.getClipBounds();
refreshFromBackbuffer(r.x - leftInset, r.y - topInset, r.width, r.height);
}
ブリットが実装されています( AWT.javaでライン371)のdrawImage()関数で使用する:ここでの問題は、drawImageメソッドは非同期とそのAであることのようです、私は仮定を作り始めるところ、これがある)
:
/** synchronized as otherwise it is possible to blit before images have been rendered to the backbuffer */
public synchronized void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2) {
discoverInsets();
try {
window.getGraphics().drawImage(((AWTPixelBuffer)s).i,
dx + leftInset, dy + topInset, // destination topleft corner
dx2 + leftInset, dy2 + topInset, // destination bottomright corner
sx, sy, // source topleft corner
sx + (dx2 - dx), sy + (dy2 - dy), // source bottomright corner
null);
} catch (NullPointerException npe) { /* FIXME: handle this gracefully */ }
}
(警告! paint/updateを介してrefreshBuffer()からblitが呼び出されますが、最初にが呼び出され、秒が発生します。
だから... blitはすでに同期されています。競合状態を防止する明白な方法は機能しません。
これまでのところ私は2つの解決策が出ているが、それらのどちらが理想的です:(:次のレンダーパス
両論の
再ブリット:パフォーマンスヒット、まだは少しを取得しますちらつき競合状態が発生した(有効画面 - >無効画面 - >有効画面)
は、ペイント/更新にブリットの代わりに設定されたリフレッシュ境界と次のパスに
短所をレンダリングする上で、それらの境界を使用しないでください。黒を取得画面が無効になったときに点滅します。メインアプリケーションのスレッドが追いついている
ここで(1)は2つの悪のうち小さいものと思われます。 編集:と(2)は動作しません、空白の画面を取得する...(1)うまく動作しますが、まだそこに潜在的に存在する問題をマスクしています。
私が望んでいて、同期の弱い理解とそれの使い方のために思い描くことができないように見えるのは、drawImage()の非同期性を何とか説明するロック機構です。
ImageObserverを使用しますか?
レンダスレッドはペイント/アップデートの外になければならないことに注意してください(Vexi、関心のある人はウェブサイトが古く、ハイパーリンクは2つしか使用できません)。シングルスレッドスクリプトモデルとレイアウトプロセス(レンダリングのサブプロセス)は、スクリプトを呼び出します。
「何が起こったのか」を意味すると思いますが、問題はまだ発生します。 blitコードをpaintメソッドにコピーしようとしましたが、同じように動作します。 (FWIWはpaintが既にrefreshFromBackBufferを使って間接的にblitと呼んでいたため実際の違いはありませんでしたが、徹底的に私が提案したことを試してみました) –
drawImageは無茶です。コードがAWTイベントハンドラスレッド(つまりペイントスレッド)で呼び出されない場合にのみ、非同期になります。そしてpaintが間接的にBlitを呼び出すとGraphicsオブジェクトを渡す必要があります –
私はdrawImageが非同期であると仮定しています(確かに状況によってはありますが、すべてではありませんか? paint()を変更してグラフィックスオブジェクトを渡し、どのような影響があるかを確認します。 blitは、メインのアプリケーションスレッドとペイントスレッドの2つのスレッドで発生しています。別の前提として、私は問題を正しく診断しています。私は間違っている可能性があり、私のポストはstackoverflow答えを得るためには少なく、2つの別々のスレッドからのblittingを適切に管理する方法を理解するために多くを得ました。 –