プロが教えるわが家の防犯対策術!

初心者です。
よろしくお願いします。

とても重く時間の掛かる処理を色んなサイトを参考にスレッドにしてみたんですけど、書き方が悪いのか、再描写がワンテンポ遅れたり、アプリケーションを複数起動したりするとフリーズしてしまったりします。
原因はメッセージループにあるような気がしてるんですが、この書き方はおかしいですか??
どのサイトから引用したのかわからなくなってしまいました。
気付いたことなどあったら何でもいいので教えて貰えたら嬉しいです!よろしくお願いします!!
thread01に重い処理が書かれてます。

int thread_call() {
  unsigned int dwThreadId[1];
  HANDLE hThread[0] = (HANDLE)_beginthreadex(
    NULL,
    0,
    ( unsigned int (__stdcall*)(void*) )thread01,
    NULL,
    0,
    &dwThreadId[0] );

  MSG msg;
  DWORD dwRet = WAIT_TIMEOUT;
  while ( 1 ) {
    dwRet = ::MsgWaitForMultipleObjects( sL, hThread, FALSE, INFINITE, QS_ALLEVENTS );
    if ( dwRet == WAIT_OBJECT_0 + sL ) {
      if ( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
        ::TranslateMessage( &msg );
        ::DispatchMessage( &msg );
      }
    } else if ( dwRet >= WAIT_OBJECT_0 && dwRet < WAIT_OBJECT_0 + sL )
      break;
  }
  CloseHandle( hThread[0] );
  hThread[0] = NULL;
}

A 回答 (2件)

>重い処理の最中でも windowのメッセージループってメッセージを受け取ってくれるんですか?



メッセージハンドラから抜けなければ受け取って(というか処理して)くれません。
今回の場合、起動したスレッドの終了を待っているのでハンドラから戻れなくなっているんですよね。
なので、時前でメッセージ処理の為のコードが入っている。と……。
# スレッドにした意味がかなりなくなりますけど。

>スレッドにしなくても大丈夫ならスレッドにしたくないです!

処理の内容次第です。
まぁ、同期処理とかちゃんとできればワーカースレッドにした方が面倒は少ないでしょう。
ワーカースレッド側でWindowsのメッセージについて考える必要はありませんし、
UIスレッドの方も処理を止められることもありませんから。

ワーカースレッドでの処理次第ですが、起動したら終了待ちしないでそのままでいいのではないかと。
# プログレスバーを表示していたり、キャンセルとかで中断させたいなら工夫が必要ですけどね。
# あと起動したスレッドの処理が終わる前に[X]ボタンで閉じられた場合…とか。

>とても重く時間の掛かる処理
がどんなモノか……に依存するってところでしょうかね。

私の場合、ワーカースレッドを中断したい場合はイベントで通知(ワーカースレッド内ではループなどのタイミングでWaitForMultipleObjects()などでイベントの状態をチェックします)して、
ワーカースレッドの終了はUIスレッドにメッセージで通知します。
# ウィンドウを閉じる…などの場合はメッセージは使えませんけど。
ウィンドウ閉じる場合はイベントでワーカースレッドに中断を通知して、ウィンドウ自体はクローズしたあとスレッドハンドルで終了を待機、その後でプロセスの終了…となりますかね。
そんなワケで…メッセージループを自前で(元々のとは別に)処理することはありませんね。

参考URL:http://rarara.cafe.coocan.jp/cgi-bin/lng/vc/vcln …
    • good
    • 0
この回答へのお礼

とっても難しいです!
サンプルのコピーばかりしていたせいで半分も理解できませんでした。。。

取りあえず今出来てあるものは一応動くので改良は後ほどにして、

> ワーカースレッドの終了はUIスレッドにメッセージで通知します。
この辺り、とても良さそうな感じがするので、理解できるように勉強しなおしてみたいと思います!

お礼日時:2012/10/14 17:26

WindowsのGUIってコトでいい…んですよね?



thread_call()ってどこから呼ばれるんでしょう?
ボタン押下したときや、メニュー選択したときなどのメッセージハンドラ中から…でしょうか?
であれば、そのハンドラから戻るのはthread01()の処理が終わった後。
ということになります。

幸いにして時前でメッセージループを回していますので、固まることはなさそう…ですが……
あんましスレッド作った意味がなさそうですねぇ。

>再描写がワンテンポ遅れたり、アプリケーションを複数起動したりするとフリーズしてしまったりします。

複数起動については別に問題(リソースの取得で…とか)があるのではないか…と思われますが……反応が悪いのは
>dwRet = ::MsgWaitForMultipleObjects( sL, hThread, FALSE, INFINITE, QS_ALLEVENTS );
ではないですかね。
http://msdn.microsoft.com/ja-jp/library/cc429261 …
QS_ALLEVENTSということは、
>入力メッセージ、WM_TIMER メッセージ、WM_PAINT メッセージ、WM_HOTKEY メッセージ、ポストされたメッセージのいずれか
がこないとココで止まります…よね?
入力メッセージとか以外にもいろんなメッセージが流れているハズ…ですが。

ワーカースレッドを作るのであれば、_beginthreadex()でスレッド作った後は、そのまま抜けてしまってよいかと。
スレッドの終了はメッセージでGUIに通知する。という方法になるかと思われますが…。
#define WM_THREADCOMPLETE (WM_APP) とかで独自に扱うメッセージを定義して…とか。
もちろん、起動するスレッドにはそれを通知するHWNDを渡す必要がありますけど。

ハンドル保持しておいて、WM_TIMER辺りでWaitForSingleObject()でチェックする。なんてのもアリでしょうかね。タイアウトを0にしておけばオブジェクトの状態確認できますし。
# まぁ、このままでMsgWaitForMultipleObjects()ではなくWaitForSingleObjectュョでスレッドの状態を取得する。というのもありでしょう。
    • good
    • 0
この回答へのお礼

お返事ありがとうございます!

windowsのGUIってことでした。
thread_callはボタンを押したときに呼ばれるようになってます。
はじめはスレッドにせず作ってたんですけど、処理が終わるまでwindowを動かしたり最小化したり出来なくなってしまったのでスレッドにしてみました。
重い処理の最中でも windowのメッセージループってメッセージを受け取ってくれるんですか?
感覚で処理が終わるまでは何しても受け取ってくれないものだと思っていました。
書き方が悪いだけなんでしょうか。。
スレッドにしなくても大丈夫ならスレッドにしたくないです!

お礼日時:2012/10/14 15:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!