マルチスレッドで描画する方法について – プログラミング – Home

マルチスレッドで描画する方法について
 
通知
すべてクリア

マルチスレッドで描画する方法について


mAro
 mAro
(@mAro)
ゲスト
結合: 23年前
投稿: 8
Topic starter  

mAroです。

MFCを使ったMDIプログラムを書いています。
親ウィンドウと子ウィンドウで描画を行う際、
親の方の描画に非常に時間がかかる処理をしているため
子の方の描画がかなり遅れてしまい、
マルチスレッドで描画させようと思いましたが、詰まってしまいました。

CDC *tmp // スレッドで参照する方法がわかりませんでした。
class ParentView : public CView
class ChildView : public CScrollView

UINT ThreadDraw(LPVOID pParam){
// 描画関数の宣言省略
tmp->MoveTo(X1,Y1);
tmp->LineTo(X2,Y2);
}
void ParentView::OnDraw(CDC *pDC){
tmp=pDC;
AfxBeginThread(ThreadDraw,this);
}
void ChildView::OnDraw(CDC *pDC){
// 描画関数の宣言省略
pDC->MoveTo(X1,Y1);
pDC->LineTo(X2,Y2);
}

2つのビューの関係はこんな感じになっています。
親ウィンドウの描画でいつもプログラムが落ちてしまいます。
デバッグモードでtmpの中身を見たところ、ハンドルが「???」になっていました。
(たまに何かの拍子にハンドルが入ってることもあるが結局は落ちる)

マルチスレッドプログラミングは初めてでデバッグ方法もわからず
どうしようもない状態なので、ご教授願います。


引用解決済
トピックタグ
かんな
 かんな
(@かんな)
ゲスト
結合: 23年前
投稿: 4
 

MFCオブジェクトはスレッドセーフにできてないので
オブジェクトを渡すよりハンドルを渡した方がいいと思います。

あと、OnDrawから抜けるとpDCは無効になります。
MFCソースのOnDrawを呼び出すところを見ればわかります。


返信引用
mAro
 mAro
(@mAro)
ゲスト
結合: 23年前
投稿: 8
Topic starter  

mAroです。
返信遅れてすいません。

CDC *tmp;
class ParentView : public CView
class ChildView : public CScrollView

void ParentView::MyDraw(CDC *pDC){
pDC->MoveTo(X1,Y1);
pDC->LineTo(X2,Y2);
}
UINT ThreadDraw(LPVOID pParam){
// 描画関数の宣言省略
ParentView *pView = (ParentView*)pParam;
pView->MyDraw(tmp);
return 0;
}
void ParentView::OnDraw(CDC *pDC){
tmp=pDC;
AfxBeginThread(ThreadDraw,this);
}
void ChildView::OnDraw(CDC *pDC){
// 描画関数の宣言省略
pDC->MoveTo(X1,Y1);
pDC->LineTo(X2,Y2);
}

このようにプログラムを書き換えたことにより、
ハンドルはきちんと戻るようになりました。(デバッグ時で確認する限りは…)
しかしやはり親ウィンドウの描画の途中で落ちてしまいます。
デバッグで1行ずつ描画させていくとなぜか無事に描画できます。
MFCでマルチスレッドを使うこと自体、難しいのでしょうか。


返信引用
渋木宏明(ひどり)
 渋木宏明(ひどり)
(@渋木宏明(ひどり))
ゲスト
結合: 22年前
投稿: 196
 

>しかしやはり親ウィンドウの描画の途中で落ちてしまいます。

同一のDCへの同時アクセスは避けた方がいいと思いますよ。
デバッグもしづらいんで、ハマると思います。

(1) 各スレッドにはメモリDCを渡し、そこに描画させる。
(2) 描画処理が完了したらプライマリスレッドに通知を行う。
(3) プライマリスレッドで仮想画面を実画面に BitBlt() する。

なんて手順にした方が面倒ごとが避けられると思います。


返信引用
mAro
 mAro
(@mAro)
ゲスト
結合: 23年前
投稿: 8
Topic starter  

仮想画面に書き込むために
CDC *pVDC;
pVDC=(CDC*)malloc(sizeof(CDC));
と記述して、これに描画し、
OnDraw()中で
pDC->BitBlt(0,0,640,280,pVDC,0,0,SRCCOPY);
としたのですが、描画されませんでした。
(0,0,640,280)は親ウィンドウの領域です。
また子ウィンドウの描画途中で落ちてしまいます。


返信引用
いぷ
 いぷ
(@いぷ)
ゲスト
結合: 23年前
投稿: 6
 

>pVDC=(CDC*)malloc(sizeof(CDC));

コンストラクタが走らないので正常に動きません。
newを使ってください。


返信引用
mAro
 mAro
(@mAro)
ゲスト
結合: 23年前
投稿: 8
Topic starter  

>コンストラクタが走らないので正常に動きません。
>newを使ってください。

pVDC = new CDC();
としたところ、

CPen newPen ;
CPen *oldPen ;
newPen.CreatePen( PS_SOLID, 1, RGB( 0, 0, 255 ) ) ;
oldPen = pVDC->SelectObject( &newPen ) ;

の pVDC->SelectObject(&newPen) で落ちてしまいます。
具体的には
CDC::SelectObject関数内の
ASSERT(m_hDC != NULL) で落ちます。


返信引用
BQ
 BQ
(@BQ)
ゲスト
結合: 22年前
投稿: 2
 

new CDC() としただけでデバイスコンテキストは作成されていません。
CDC::CreateCompatibleDC()
などを用いてデバイスコンテキストを初期化する必要があります。

このとき結びついたデバイスコンテキストリソースハンドルが CDC::m_hDC に保存されます。
初期化が行なわれていないと m_hDC が NULL のままなので、
ASSERT(m_hDC != NULL);
で落ちることになります。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました