描画ルーチンに時間がかかるので別スレッドにて処理したいのですが、
描画スレッド実行中に再描画命令がきた時どうしたらいいのか分かりません。
一応、こんなコードを考えてみました。
bool flag; // trueにセットするとスレッドを中断するフラグ(グローバル変数)
ReDraw(HWND hwnd) // 再描画する
{
DWORD code;
if(GetExitCodeThread(hThread, &code) == STILL_ACTIVE){
flag = true;
WaitForSingleObject(hThread, INFINITY);
}
DWIORD id;
flag = false;
hThread = CreateThread(NULL, ThDrawFunc, (LPVOID)hwnd, 0, &id):
}
DWORD ThDrawFunc(LPVOID p) // 描画ルーチン
{
for(; ; ){ // これが描画ルーチンです。
if(flag) break; // 中身は省略しています。
} //
PostMessage(hwnd, WM_APP, 0, 0);
EndThread(0);
return 0;
}
hwndのWM_APPはこんな感じです。
WM_APP:
CloseHandle(hThread);
break;
上のコード、CloseHandle()はWM_APPで処理してますが、スレッドを中断するのにflagを
trueにした場合、WaitForSingleObjectから抜けて新たにCreateThreadを実行するのと
PostMessageされてCloseHandle()するのがどちらが早いかこれだと不定でしょう。
スレッドを中断できて、かつ確実に閉じるようにするにはどうしたらいいのでしょうか?
描画ルーチンを別スレッドにしたい時の一般的な手法があれば知りたいです。
環境はWinXP VC++6SP6 MFC未使用です。
別スレッドを起こしても ReDraw の中で
Wait ~したら結局描画完了時間は同じ
(オーバヘッドの分より遅くなる?)かな。
別スレッドにする前段階として、まずは「裏画面」について
調べてみると幸せになれるかも。
んー、つまり異なるスレッドからhThreadという同じ変数にアクセスするのが問題って
事かな。
だとしたらクリティカルセクションなりミューテックスなりを使って抑止すればOK。
>Wait ~したら結局描画完了時間は同じ
フラグを立てればforループからループカウントが残っていても抜けるって意味だと思う
ので完了時間は同じではないのでしょう。(違ってたらごめんなさい)
Qoolさんがおっしゃる「裏画面」の意味がもし分からないのでしたら確かにスレッド
うんぬん言う以前の問題ですが、どうなのかなぁ。
MFCじゃないんですけど参考になれば
カットシステム 「Visual C++ .NETではじめる Win32 API
システム プログラミング」
と言う本があり
「スレッドの実用例」に同等の説明があります、参考にしてみては如何でしょうか
描画を単にスレッド化しても問題の解決にはならないような気がします。
描画が遅いと言うのはともかく、スレッド化するのであれば描画によって
他の処理が進まないので描画をスレッド化する事で他の処理を並行処理する
と言うのが目的になると思います。
但し、この場合は描画された結果が表示されるよりも他の処理を進める事が重要で
場合によっては描画処理はスキップされてもいいとか、
描画処理は後れて表示を行ってもよいという話で無いと繋がりません。
毎回の描画結果を確実に表示する必要があるならスレッド化しても意味が無いでしょう。
描画処理が遅い事が問題で描画処理を早くしたいのであれば、
描画処理そのものを見直して高速化しないと問題の解決にはならないと思います。
基本的には、既に上がっているバックバッファを使った描画が一般的です。
これでも遅いと言うのであれば、DirectXやOpenGLと言った高速な描画ライブラリを
使用するか、独自の高速描画ルーチンを作成して使用すると言ったアプローチを
行う必要があるかもしれません。
因みにReDraw内でWaitForSingleObject(hThread, INFINITY);を使って
中断時の終了待ちをしているのですからこれから帰ってきたら
Closeしていいのではないですか?
スレッド側のPostMessage(hwnd, WM_APP, 0, 0);は終了通知だと思いますが、
終了通知が必要なのは、WaitForSingleObjectで待ち続ける事が出来ないような
場合なのでこれが生きるのは正常終了時だけでいいと思います。
その場合でもWM_APPを受けた後、WaitForSingleObjectで終了待ちをいれた方が
安全だと思います。実際の終了確認後、Closeでいいでしょう。
ただ、この描画スレッドって正常終了するんですか?
永久ループしてるように見えますが。
みなさん、ありがとうございます。
Qool様
裏画面に関しては理解しています。
いま考えているのはスレッド専用の裏画面をつくり、WM_PAINT用の裏画面と分けようか、
という事です。これによりスレッドで描画中でもWM_PAINTに対応できるかと思います。
SunPac様
スレッドで同じ変数にアクセスするのは確かに問題ですね。
クリティカルセクションやミューテックスで防止するのは必須でしょう。
中断の意味はおっしゃる通りです。
wood様
>カットシステム 「Visual C++ .NETではじめる Win32 API
> システム プログラミング」
是非参考にしたいと思います。
PATIO様
スレッド化の目的は描画中に何もできなくなるのを防止するのと描画を中断して再描画
できるようにする事ですので、問題の解決になると思います。(説明不足でした)
DirectXは7.0で私の知識はとまってまして、OpenGLに関しては無知です。
興味はあるので調べてみようとは思います。
>因みにReDraw内でWaitForSingleObject(hThread, INFINITY);を使って
>中断時の終了待ちをしているのですからこれから帰ってきたら
>Closeしていいのではないですか?
確かに言われてみればそうですね、気づきませんでした。
あと無限ループの件はfor(; ;)の部分の事でしょうが、これは省略しただけです。
実際は図形オブジェクトのポインタのリストを頭から順に書いています。
いろいろ参考になりました、ありがとうございます。