none
SetTimerについて RRS feed

  • 質問

  • いつもお世話になっております。

    Windows7 Enterprise 64bit + VS 2010 Professional のVC++でSDKで開発を行っております。
    SetTimerに関して少し質問があります。

    現在開発中のアプリの中で、WinsockによるTCPで"Hello"というパケットをやり取りし、その結果をダイアログ上のエディットボックスに表示させるプログラムを作っています。

    このHelloパケットを飛ばす間隔が1秒なのですが、メインダイアログのプロシージャのほうでWM_TIMERを受け取るようにしているのですが、これだと、コントロールの操作(ボタンクリック)などが必ずもっさりしてしまって、ちょっと困っています。
    SetTimerの最後の引数に、Helloパケットのやり取りをする関数のポインタを渡した場合、一時的に新たなスレッドが生成されるのでしょうか?

    というのも、別スレッドとして実行される場合、メインダイアログ上のコントロールに対してスレッド関数内でメッセージを送ってしまうと、デッドロックになってしまいますよね?
    そうすると、メインダイアログに対してPostMessageを送る形になると思います。

    そうでなければ、そのまま親ウインドウのハンドルからSetDlgItemTextなどを直接実行できると思うのですが、どちらだかわからないため判断ができず…

    Timerprocの説明をみても、スレッドが生成される/されないのような記述が見当たらなく・・・
    (いうまでもなく生成されるから記載されていないのかもしれませんが^^;)

    いかがなものなのでしょう?
    それとも、Timerprocを使わずに、解消する方法などがあるのでしょうか?

    ご存知の方いらっしゃいましたら、ご教授をお願いいたします。

    2011年2月25日 6:25

回答

  • SetTimerでは一切のスレッドは作られません。このタイマーのタイムアウトは
    メッセージで取得する場合も関数にコールバックされる場合もメッセージキュー
    経由となります。従ってメインのメッセージキューが停止しているとタイムアウトを
    受け取れません。
    Timerを実装して「もっさり」するのは、送信側ですか、受信側でしょうか。
    どちらの場合でも、タイマーインターバルが来る毎にソケットを作ったり
    コネクトしたりすると、オーバーヘッドが大きすぎてお話になりませんです。
    当然メインの応答性に影響がでます。
    通信の確立と解除は、送信内容と無関係に実装したほうが良いでしょう。
    また、受信タイミングをタイマーでコントロールするのは確実に破綻するので
    やめましょう。受信スレッドを作成してイベントを使って受信し、
    自前のバッファなり、キューなり、リングバッファなりに保管しましょう。
    再描画タイミングはタイマーインターバルを利用する方法で十分ですが、
    本件の様に暇な場合は先の受信イベントで再描画をかけるのが吉だと考えます。
    • 回答としてマーク どらちん 2011年2月25日 10:29
    2011年2月25日 6:46
  • SetTimer 関数の解説にはっきり書かれてますけど。

    TimerProc コールバック関数を指定すると、既定のウィンドウプロシージャは WM_TIMER メッセージを処理する際にそのコールバック関数を呼び出します。したがって、WM_TIMER メッセージを処理する代わりに TimerProc 関数を使う場合も、呼び出し側スレッド内でメッセージをディスパッチ(転送)する必要があります。

    要するに、単に「WindowProc で WM_TIMER の時にメソッドを呼び出す」部分を DefWindowProc が肩代わりしてくれるだけです。

    • 回答としてマーク どらちん 2011年2月25日 10:29
    2011年2月25日 6:46

すべての返信

  • SetTimerでは一切のスレッドは作られません。このタイマーのタイムアウトは
    メッセージで取得する場合も関数にコールバックされる場合もメッセージキュー
    経由となります。従ってメインのメッセージキューが停止しているとタイムアウトを
    受け取れません。
    Timerを実装して「もっさり」するのは、送信側ですか、受信側でしょうか。
    どちらの場合でも、タイマーインターバルが来る毎にソケットを作ったり
    コネクトしたりすると、オーバーヘッドが大きすぎてお話になりませんです。
    当然メインの応答性に影響がでます。
    通信の確立と解除は、送信内容と無関係に実装したほうが良いでしょう。
    また、受信タイミングをタイマーでコントロールするのは確実に破綻するので
    やめましょう。受信スレッドを作成してイベントを使って受信し、
    自前のバッファなり、キューなり、リングバッファなりに保管しましょう。
    再描画タイミングはタイマーインターバルを利用する方法で十分ですが、
    本件の様に暇な場合は先の受信イベントで再描画をかけるのが吉だと考えます。
    • 回答としてマーク どらちん 2011年2月25日 10:29
    2011年2月25日 6:46
  • SetTimer 関数の解説にはっきり書かれてますけど。

    TimerProc コールバック関数を指定すると、既定のウィンドウプロシージャは WM_TIMER メッセージを処理する際にそのコールバック関数を呼び出します。したがって、WM_TIMER メッセージを処理する代わりに TimerProc 関数を使う場合も、呼び出し側スレッド内でメッセージをディスパッチ(転送)する必要があります。

    要するに、単に「WindowProc で WM_TIMER の時にメソッドを呼び出す」部分を DefWindowProc が肩代わりしてくれるだけです。

    • 回答としてマーク どらちん 2011年2月25日 10:29
    2011年2月25日 6:46
  • 仲澤@失業者さん、Hongliangさん

    レス、ありがとうございます。

    >Timerを実装して「もっさり」するのは、送信側ですか、受信側でしょうか。

    申し訳ありません、書き方が悪かったですね。
    受信・応答側は、専用のスレッドを実行しています。

    送信側のほうが、一定時間ごとにConnectをして応答を要求しようとしています。
    つまり、送信側のほうでもっさりしているわけです。

    もともと、送信側もスレッドで作成していたのですが、スレッド数増えてきてしまい、スレッドの数を減らしたいと思い、Timerでうまく送信側(connetcを実行する側)だけでも切り替えられないかな~と試していた次第です。

    >要するに、単に「WindowProc で WM_TIMER の時にメソッドを呼び出す」部分を DefWindowProc が肩代わりしてくれるだけです。

    ということは、SetTimerの第一引数が同じメインダイアログのハンドルを渡していたら、結果は同じということですよね?

    やはり送信側もスレッドで実装したほうがよいのでしょうか・・・?

    2011年2月25日 8:17
  • いろいろ試してみたのですが、送信側もスレッドで実装するのが一番まともに動作するので、スレッドで実装したいと思います。

    お騒がせいたしました。
    2011年2月25日 10:29