マルチスレッドでの画像描画について

このQ&Aのポイント
  • マルチスレッドを使ってロード画面の作成を試みていますが、画像が上手く描画更新されません。
  • GameMain::LoadScreen関数内でスレッドを生成し、ローディング画面の描画を行っています。
  • 画像の描画更新がうまく行われない問題が発生しており、解決方法を求めています。
回答を見る
  • ベストアンサー

マルチスレッドでの画像描画

マルチスレッドを使ってロード画面を作ろうとしているのですが、 上手く画像が描画更新してくれません。 スレッドの中身は下記の通りです。よろしくお願いします。 HRESULT GameMain::LoadScreen() { // スレッドの生成 static bool onlyonce_createthread = FALSE; if(onlyonce_createthread ==FALSE) { hTh = (HANDLE)_beginthreadex( NULL, // SECURITY_ATTRIBUTES 構造体へのポインタ 0, // 新規スレッドのスタックサイズ &loadthread, // スレッドの実行開始アドレス this, // 新規スレッドに渡される引数リスト 0, // 新規スレッドの初期状態 (unsigned*)&thID ); // スレッドのIDを格納するためのDWORD型変数へのポインタ onlyonce_createthread =TRUE; } // ローディング画面の描画 static bool loopflg = TRUE; while(loopflg) { int threadCondition = CheckThread( hTh ); switch(threadCondition) { case THREAD_RUNNING: if(graphloaded_flg ==TRUE) { EnterCriticalSection( &m_criticalSection ); load_item = (float)(load_item/MAX_LOAD_ITEM); LeaveCriticalSection( &m_criticalSection ); d2d_control->GaugeDraw(0, 0, load_item); Sleep(100); } break; case THREAD_EXIT: loopflg =FALSE; break; case THREAD_ERROR: return E_FAIL; break; } } return S_OK; }

質問者が選んだベストアンサー

  • ベストアンサー
  • salsberry
  • ベストアンサー率69% (495/711)
回答No.1

・d2d_control->GaugeDraw(0, 0, load_item);の行は実行されていますか? ・そのときのload_itemの値はどうなっていますか? 見るからに怪しいのがload_item = (float)(load_item/MAX_LOAD_ITEM);の部分です。load_itemの値がMAX_LOAD_ITEMの値よりも小さい場合、割り算を繰り返すうちにload_itemの値がどんどん0に近付いていきます。それは意図通りですか? もう一つ、threadCondition==THREAD_RUNNING かつ graphloaded_flg!=TRUE のとき、ビジーループになってしまっています。Sleep(100);を入れる場所を変えて下さい。while()ループの先頭、CheckThread()を呼ぶ前あたりがいいんじゃないでしょうか。 本当ならSleepしながら別スレッドの状態をチェックするのではなく、適切な同期機構を使ってスレッド間のイベント通知を行うべきです。 これ以上のことは、別スレッドの処理内容や、「上手く画像が描画更新してくれません」の具体的な症状(メインスレッドがEnterCriticalSection()のところで止まってしまってその後の処理に進めないとか、描画する前にTHREAD_EXITになってループを抜けてしまっているとか)が分からないと何とも言えません。 プログラムがどこまで実行されていてそのときの変数の値がどうなっているか、デバッガを使って調べてみましたか?

rikaruna
質問者

お礼

数値の変動のところを確認してみると変数の値が変わってませんでした。 お手数をおかけしました。 ありがとうございます。

関連するQ&A

  • マルチスレッドについて・・・

    先日マルチスレッドについて質問させていただいたものですが、助言のもと動かしてうまくいったように見えたのですが、ロードしていない部分がありました。 今回はスレッドの中身もかいておきます。 ご助力お願いいたします。 unsigned int WINAPI GameMain::loadthread(void *lpx) { GameMain* gm = (GameMain*)lpx; gm->GInit();   //ロード return 0; } HRESULT GameMain::LoadScreen() { // スレッドの生成 static bool onlyonce_createthread = FALSE; if(onlyonce_createthread ==FALSE) { hTh = (HANDLE)_beginthreadex( NULL, 0, &loadthread, this, 0, (unsigned*)&thID ); onlyonce_createthread =TRUE; } // ローディング画面の描画 static bool loopflg = TRUE; while(loopflg) { int threadCondition = CheckThread( hTh ); switch(threadCondition) { case THREAD_RUNNING: if(graphloaded_flg ==TRUE) //2D画像のロードが終わったら { EnterCriticalSection( &m_criticalSection ); float keep_item = (float)(load_item/MAX_LOAD_ITEM); LeaveCriticalSection( &m_criticalSection ); d2d_control->GaugeDraw(0, 0, keep_item); //画像の描画関数 } break; case THREAD_EXIT: loopflg =FALSE; break; case THREAD_ERROR: return E_FAIL; break; } } float keep_item = (float)(load_item/MAX_LOAD_ITEM); d2d_control->GaugeDraw(0, 0, keep_item);  //画像の描画関数 return S_OK; }

  • マルチスレッドについて

    私はいまマルチスレッドの勉強をしているのですが、ビルドが通るのに実行結果がおかしい状況に陥っています。 ロード画面の処理なのですが、プライマリスレッドでロード画面を描画し、セカンダリスレッドでロード処理を行おうとしています。 問題は、ロードが途中で止まることとロード画面を描画できません。 多分下記の関数が悪いとは思うのですがどうか、ご助力おねがいします。 HRESULT GameMain::LoadScreen() { // スレッドの生成 static bool onlyonce_createthread = FALSE; if(onlyonce_createthread ==FALSE) { hTh = (HANDLE)_beginthreadex( NULL, 0, &loadthread, this, 0, (unsigned*)&thID ); onlyonce_createthread =TRUE; } // ローディング画面の描画 static bool loopflg = TRUE; while(loopflg) { int threadCondition = CheckThread( hTh ); switch(threadCondition) { case THREAD_RUNNING: if(graphloaded_flg ==TRUE) { EnterCriticalSection( &m_criticalSection ); float keep_item = (float)(load_item/MAX_LOAD_ITEM); LeaveCriticalSection( &m_criticalSection ); d2d_control->GaugeDraw(0, 0, keep_item); } break; case THREAD_EXIT: loopflg =FALSE; break; case THREAD_ERROR: return E_FAIL; break; } } float keep_item = (float)(load_item/MAX_LOAD_ITEM); d2d_control->GaugeDraw(0, 0, keep_item); return S_OK; }

  • スレッドの終了を知りたい(WindowsAPI)

    CreateThread()で作成したスレッドの終了を知りたい (具体的には、スレッドが終了するまで待機したい)のですが、 うまくいかず困っています。WindowsAPIに関する本やネットで調べた ところ、WaitForSingleObject()が適用できると考え、 以下のようなプログラムを作成したのですが、 元のスレッドがWaitForSingleObject()のところで 止まると同時に、CreateThread()で作成されたThread_1()も 止まってしまいます。アドバイスいただけますでしょうか。 ----プログラム(該当部分)ここから---- DWORD Thread_1(LPVOID param) {  int i;  char buff[128];  /* iが99のときのみ終了してよい */  while(g_iFlg == 1)  {   for(i = 0; i < 100; i++)   {    Sleep(100);    wsprintf(buff, "%d", i);    SetDlgItemText((HWND)param, IDC_STATIC_1, buff);   }  }  ExitThread(0);  return 0; } BOOL CALLBACK Proc_2(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {  switch(uMsg)  {   case WM_INITDIALOG:    g_iFlg = 1;    g_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread_1, (LPVOID)hDlg, 0, &g_dwThread);    return TRUE;   case WM_COMMAND:    switch(LOWORD(wParam))    {     case IDC_BUTTON_CANCEL:     case IDCANCEL:      g_iFlg = 0;      WaitForSingleObject(g_hThread, INFINITE);      CloseHandle(g_hThread);      EndDialog(hDlg, 0);      return TRUE;    }  }  return FALSE; } ----プログラム(該当部分)ここまで----

  • Win32APIでのスレッド処理

     こんにちは。 質問ですが、自分の環境はWindowsXP SP3 VisualStudio.NET2005 でのC++でのプログラミングです。 まず、スレッド作成をするために、_beginthreadexを用いているのですが、このやり方で、5,6個のスレッドを作成すると処理が逆に重くなってしまいました。 このスレッドは排他制御をしていないものです。 以下にソースの一部を載せます。 ///////////////////////// // スレッド作成 BOOL TestFunc::ThreadRegist(void) { UINT thID = 0; if((hThread = (HANDLE)_beginthreadex(NULL, 0, &TestFunc::tRunLauncher, this, 0, &thID)) == 0) { return FALSE; } return TRUE; } ///////////////////////// // スレッド void TestFunc::ThreadRun(void) { ras.Sprite(ene.d, ene.m, ene.s);//処理の重い画像処理 thflag = true; _endthreadex(0); } // これがクラス class TestFunc : public CTEST01 { bool rasf; bool thflag; WORD set; EffectRaster ras; double RX, RY; HANDLE hThread; static UINT WINAPI tRunLauncher(void* vp) { reinterpret_cast<TestFunc*>(vp)->ThreadRun(); return 0; } void ThreadRun(); BOOL ThreadRegist(); public: TestFunc(double x, double y, WORD type); }; このオブジェクトを多くて5~6個作っています。 上記の場所をスレッドにしない場合、逆に処理が軽くなるんです。 スレッドが5から6個でも処理が重ければ影響が出るのでしょうか? しかしそれでもスレッドにしない場合より重くなる理由が分からないでいます。   詳しい方がいらっしゃいましたらどうぞよろしくお願い致します。 m( )m

  • Mutexの次の使い方で

    typedef struct{ HWND hwnd;BOOL th_end;HANDLE hmutex; } DATA, *PDATA; /////////////////////////////////////// static HANDLE hThread1,hThread2; DWORD threadID1,threadID2; static DATA data; static HANDLE hMutex; switch (msg) { case WM_CREATE: //hMutex= //CreateMutex(NULL,FALSE,NULL); data.hwnd = hWnd; data.th_end = FALSE; data.hmutex = hMutex; hThread1=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)Thread1, (LPVOID)&data, 0,(LPDWORD)&threadID1); hThread2=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)Thread2, (LPVOID)&data, 0,(LPDWORD)&threadID2); /*x*/hMutex= /*x*/CreateMutex(NULL,FALSE,NULL); break; とするのは正しくて/*x*/の行を削除して//をとり hMutexの位置を前に持ってくるのは間違っているのでしょうか?

  • GDI+で高速な描画

    GDI+を利用してお絵かきツールのようなものを作成しようと思っています。 しかしdrawImage()での画面への描画が非常に遅いようで、描いてみると線がカクカクしてしまいます。 アンチエイリアスやアルファブレンドが必要なのでGDI+を利用したいのですが、どうにか高速に描画させる方法はないでしょうか? 下記は現在のソースの一部です。 static Bitmap *offscreenBitmap //描画処理はこっちに static Graphics *offscreen; static Graphics *onscreen; //画面表示用 static RECT rect; //クライアント領域 static POINTS posPts,pts; //一つ前と現在のマウス座標 static BOOL bLButtonDown; Pen nomalPen(Color(100,0,0,0), 1); //描画用ペン switch(msg){  case WM_CREATE:   GetClientRect(hWnd,&rect);   offscreenBitmap = new Bitmap(rect.right, rect.bottom); //ビットマップ生成   offscreen = new Graphics(offscreenBitmap);   offscreen->SetCompositingMode(Gdiplus::CompositingModeSourceOver);   offscreen->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);//アンチエイリアス有効化   offscreen->Clear(Color(255,255,255)); //初期化   onscreen = new Graphics(hWnd); //ウインドウ表示用   onscreen->SetCompositingMode(CompositingModeSourceCopy);   break;  case WM_LBTTONDOWN:   bLButtonDown = TRUE;   posPts=MAKEPOINTS(lp)   break;  case WM_MOVE:   pts=MAKEPOINTS(lp)   if(bLButtonDown){    offscreen->DrawLine(&nomalPen, posPts.x, posPts.y, pts.x, pts.y);//線描画    posPts.x=pts.x;    posPts.y=pts.y;   }   InvalidateRect(hWnd,&rect,0);//ウインドウを更新   break;  case WM_PAINT:   onscreen->DrawImage(offscreenBitmap,0,0);//画面に書き出し   break; }

  • マルチスレッドプログラミングについて

    マルチスレッドプログラミングについていくつか教えて下さい。 マルチスレッドの基礎がまだ分かってないので初心者でも分かり易いようにお願いします。 1:イベントオブジェクトについて教えて下さい。 「イベントオブジェクト」の概念がよく分かりません。 ○シグナル状態と非シグナル状態とはどういう状態なのでしょうか? ○自動リセットの場合ではどのタイミングで切り替わっているのでしょうか?(下記のソースの場合) ○手動リセットの場合ではどのタイミングで切り替えればよいのでしょうか?(下記のソースの場合) 2:CloseHandle() と ExitThread() について教えて下さい。 ○この2つの関数の役割の違いについて教えて下さい。 「スレッドハンドルを閉じる=スレッドを終了」ではないのでしょうか? また、これらの関数実行時にシグナル状態は気にする必要はありますか?(シグナル状態にしなくてよいのか?) 下記のソースは簡略化のためかなり省略されています。 DWORD WINAPI ThreadProc( DWORD i ) { while( true ) { DWORD r = WaitForMultipleObjects( 2, hEvent, FALSE, INFINITE ); if( r == WAIT_OBJECT_0 ) { // 処理1 } else if( r == WAIT_OBJECT_0 ) { // 処理2 } else { ExitThread( TRUE ); // スレッド終了 } } } void MainProc() { // 自動リセットのイベントオブジェクト作成 for( int i=0; i<2; i++ ) { hEvent[i] = CreateEvent( NULL, FALSE, FALSE, NULL ); } // スレッドを作成 hThread = CreateThread( NULL, 0, ThreadProc, NULL, 0, &dwThreadID ); }

  • マルチスレッドプログラミングについて

    こんばんわ。 マルチスレッドプログラミングを行なっています。開発環境はVC++.NET2003でC言語を用いてコンソールアプリケーションを勉強中です。 以下にプログラムを示します。 以下のプログラムは、 (1)ThAとThBが交互に1~10までカウントUP (2)ThBだけが11~20までカウントUP (3)ThAはTh11から、ThBは21からカウントUP というプログラムを記述したつもりなのですが・・・実行開始後は(1)から(3)のように表示できるのですが、それ以降はThAとThBが交互に表示されてしまいます。 (1)から(3)を繰り返す記述の仕方はありますでしょうか? よろしくお願い致します。 HANDLE hEvent[3]; unsigned __stdcall ThB(void *lpx){ int j; int l=1; for(j=1;j<100;j++){ Sleep(100); printf("ThB%d\n",j); if(l%20==0){ SetEvent(hEvent[0]); } l++; } return 0; } unsigned __stdcall ThA(void *lpx){ int k; int j=1; for(k=1;k<100;k++){ Sleep(100); printf("ThA%d\n",k); if(j%10==0){ WaitForSingleObject(hEvent[0],INFINITE); } j++; } SetEvent(hEvent[2]); return 0; } int main(int argc ,char *argv[]){ unsigned int thID[2]; HANDLE hTh[2]; int i; hEvent[0] = CreateEvent(NULL, TRUE, FALSE, "CH0"); hEvent[1] = CreateEvent(NULL, TRUE, FALSE, "CH1"); hEvent[2] = CreateEvent(NULL, TRUE, FALSE, "MAINEVENT"); hTh[0] = (HANDLE)_beginthreadex(NULL, 0, ThA, NULL, 0, &thID[0]); hTh[1] = (HANDLE)_beginthreadex(NULL, 0, ThB, NULL, 0, &thID[1]); WaitForSingleObject(hEvent[2], INFINITE); for(i=0;i<2;i++) CloseHandle(hTh[i]); return 0; }

  • 2重Func禁止。クリセク。セマフォ。

    MyFunc( ) の実行中は WM_LBUTTONDOWN を無視されるように しようと思いました。 LRESULT CALLBACK WndProc(… {  static bool b = TRUE;  switch(msg){  case WM_LBUTTONDOWN:   if(b){    b = FALSE;    MyFunc( ); //  MessageBox(hWnd, "", "", MB_OK);    b = TRUE;   }  break; でもこれでは、例えば MyFunc( ) が実行中に3回クリックすると その後に MyFunc( ) は3回実行されてしまいます。 MessageBox( ) を使えばうまくいくけと、それは使いたくありません。 できるだけ簡単なソースで、 MyFunc( ) の実行中のクリックで、後で MyFunc( ) が 実行されないようにするにはどこを直したらいいですか?

  • boost::threadでのjoinについて

    スレッド用に作成したループ用関数を自前で終了させてからjoinをすると、thread::m_joinableがfalseになりjoinでassertが出ることがあります。 問題の処理を簡単なモデルで説明しますと、 bool g_finish(false); void thread_loop(void) {  while(true)  {   ...   if(g_finish) break;  } } int main(void) {  boost::thread th(thread_loop);  sleep(100000);  g_finish=true;  th.join(); // assert  return 0; } といった感じになります。実際にはスレッド管理クラスにおいて複数のス レッドが管理されています。 冗長ですが、このような処理をするときにjoinのときにm_joinableがfalse になりassertが出るという事態です。 どなたが知識をお持ちの方がおられましたらご教授願えれば幸いです。

専門家に質問してみよう