ページ 11

再描画要求

Posted: 2006年9月26日(火) 16:01
by kobu
ゲームみたいなものを作っていて、最近開発環境を変えたのですが、ウィンドウメッセージを受け取るスレッドと別にゲームメインスレッドをつくっていたのですが、GDI関係で困ってしまいました。

メインスレッドで
InvalidateRect()
を使って画面の再描画要求をした後にTextOutやRectangleでaDC(デバイスコンテキストハンドル)に絵画しようとしたときに

ウィンドウメッセージスレッドは、RADツールの
Sub MainWnd_Paint(hDC As DWord)
BitBlt(hDC,0,0,MX,MY,aDC,0,0,SRCCOPY)
End Sub
(MX:MYはウィンドウの幅と高さです。)
を実行中で、メインスレッドのTextOutなどに渡したaDCが「無効なハンドル」とされて
TextOutされないという現象が発生しました。

前の開発環境(WinXP SP2 Intel Celeron M 1.0GHz AB 5.0CP3)ではそういうことはなく、今の開発環境(WinXP SP2 Intel Pentinum 4 2.93GHz AB CP3)で起こるようになって大変困っています。

対策としてはスレッドの優先度を変えたり、TextOutの前にSleepをつけたりとしたんですが、この現象を完全に防ぐことができませんでした。

ネットで3日調べてもわかりませんでした。
わかりにくい質問かもしれませんが、どなたかご教授おねがいします。

Posted: 2006年9月26日(火) 18:52
by konisi
解決策は解りませんが・・・。
CP版で発生した物は、こちらではなくバグ報告版で報告してください。
4.24や4.13では大丈夫ですか?

Posted: 2006年9月26日(火) 23:33
by OverTaker
複数のスレッドからグローバル変数(複数のスレッドで使っている変数等)にアクセスしてないでしょうか?
マルチスレッドの場合、それをやるとアクセスするタイミングが衝突してしまい問題があるので、クリティカルセクションというものを使う必要があるそうです。

私自身、クリティカルセクションを使ったことないので詳しくはわかりませんが、ここの過去ログにいくつか記事があります。参考にしてはいかがでしょうか?

Posted: 2006年9月27日(水) 01:46
by NoWest
何事もソースを見てみないことには何とも言えませんね。

全体でなくてもいいから、
aDCとやらが関わっている部分を抜き出して乗っけてもらえると判りやすいと思う。
自分もバグに気付きやすいし

Posted: 2006年9月27日(水) 13:49
by Kobu
konisi様、OverTaker様、NoWest様返信ありがとうございます。

メインスレッドでは

コード: 全て選択


InvalidateRect(hMainWnd,ByVal 0,0)---①

---500行くらいコードがある---(この間aDCは関係なし)
②
BitBlt(cDC,0,0,MX+1,101,aDC,0,MY-100,SRCCOPY)
SelectObject(aDC,hPenb)
SelectObject(aDC,brh)
Rectangle(aDC,30,MY-100,MX-30,MY-30)
TextOut(aDC,50,MY-80,i,lstrlen(i))
InvalidateRect(hMainWnd,ByVal 0,0)
ウィンドウメッセージスレッドはふつうにRADツールでつくって、先ほどのコードを足したものです。

多分自分が実験した結果では、①で呼び出した再描画要求で描画されるまでにTextOut などでaDCを参照してしまい。
OverTaker様が言われました「アクセスするタイミングが衝突してしまう問題」になってしまうと思うのです。

まずは、クリティカルセクションなるものを調べようと思います。
返答ありがとうございました。[/code]

Posted: 2006年9月27日(水) 19:07
by konisi
aDCの宣言部の上下付近に配列で宣言されている物はありませんか?
例えば、次のようなコードが書かれている場合には変数aは実行コード内では上書きされています。

コード: 全て選択

Dim a As Long,b(100) As Long,i As Long
i=-1
Do
    b(i)=i
    i++
    If i=100 then Exit Do
Loop
あなたのコードを見た限りでは単独スレッドのようなので、これの可能性があるのではないかなと思ったんですが。