タイマーを使うためには?

解決


勉7号  2008-10-07 09:26:18  No: 69084

お世話になっております.
今回はタイマーを使おうと思って,以下のソースを試しましたが,プログラムの目的を果たせませんでした.strボタンを押してタイマーを設定し50msecごとに同じ作業を繰り返し,stpボタンで終了させるのが目的です.

void CSampleDlg::OnButtonStr() 
{
  // TODO: Add your control notification handler code here

  SetTimer(1, 50, NULL);//タイマーの設定  50msecごとに呼び出す

  m_cStop.EnableWindow(TRUE);
  m_cStart.EnableWindow(FALSE);

}

void CSampleDlg::OnTimer(UINT nIDEvent) 
{
  // TODO: Add your control notification handler code here
  
  //----------
          作業
         //----------

  CDialog::OnTimer(nIDEvent);
}

void CSampleDlg::OnButtonStp() 
{
  // TODO: Add your control notification handler code here
  KillTimer(1);  //タイマーのストップ
  m_cStop.EnableWindow(FALSE);  //stopボタン無効
  m_cStart.EnableWindow(TRUE);  //startボタン有効
  
}

デバッグしてもdead lockだといわれてしまいます.どこまでプログラムが動いているのかは確認できませんでしたが,どこかタイマーの使い方がおかしいのでしょうか?宜しくお願いします.


tetrapod  2008-10-07 17:14:56  No: 69085

まず前提条件として Windows の WM_TIMER というのは優先順位が低く、
計測機器から測定データを定期的に取得する必然があるなどの理由で
「必ず 50msec ごとに確実に処理がなされなければならない」
という仕様を実現するためであれば、そもそも原理的に使えない代物だ
ってあたりの理解はOK?

50msec を指定しても 1000msec 以上遅れるなんてことはざら。

提示のコード断片だけだと悪いところはみつからない。
「作業」の処理に 50msec 以上かかっていたりする可能性とかは検討済み?


そだ  2008-10-07 19:27:35  No: 69086

どこでデットロックするの?それ書かないと。


そだ  2008-10-07 19:29:27  No: 69087

あ、失礼。確認できないのか。
間隔長くして(1時間とか)OnTimer()の中をトレースしてみては?


Hazard52  2008-10-07 23:29:10  No: 69088

MFCはあまり使っていないので、間違えているかもしれませんが、
CSampleDlg::OnTimer()の中で処理が完結しているのでしたら、
CDialog::OnTimer(nIDEvent)は不要なのではないでしょうか。


勉7号  2008-10-08 04:38:34  No: 69089

tetrapodさん,そださん,Hazard52さんご返信ありがとうございます.

WM_TIMERがそんなにあやふやなものだとは,知りませんでした...
時間を守らせるには他の方法でやる必要がありそうです.

「作業」の処理に対して十分な時間をあけて,タイマーを設定しているので,作業が終わる前にタイマーがきてしまうことはないと思います.

TRACEで確かめたところ,OnTimerが実行されていないようではあります.

CDialog::OnTimer(nIDEvent)に関してですが,消してみたりしましたが,うまく行きませんでした.

あと理由は分かりませんが,dead lockはデバッグに表示されなくなりました.


そだ  2008-10-08 13:23:25  No: 69090

>TRACEで確かめたところ,OnTimerが実行されていないようではあります.
ブレークポイントの設置個所はOnTimer内だけですか?
SetTimerを実行しているところもトレースしていると最初の1回を見逃すかもしれません。
それでもタイマーが起動していないというならば、SetTimerの戻り値を調べ正常に実行されているか確かめるべきです。

>あと理由は分かりませんが,dead lockはデバッグに表示されなくなりました.
タイマの間隔を長くした後でしょうか。同時に2つ以上のスレッドが動いていないならばデッドロックはその定義上起こりえません。


rin  2008-10-08 19:39:47  No: 69091

作業部分を抜いたソースで試すか
新しいプロジェクトをつくって、タイマーだけの実験をしてみてはどうでしょうか?


勉7号  2008-10-09 23:21:31  No: 69092

そださん,rinさんご返信ありがとうございます.

作業部分を抜かしたり,あちこちtraceを入れてみましたが,やはりOnTimerが実行されていないようだったので,どこで何か宣言し損ねてるのかと思い,色々調べてメッセージマップのところにWM_TIMER()を追加したらプログラムが動きました.参考にしていた本に記載がなかったので,何も入れていませんでした...

BEGIN_MESSAGE_MAP(CSampleDlg, CDialog)
  //{{AFX_MSG_MAP(CTakeuchiDlg)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_BN_CLICKED(IDC_BUTTON_STR, OnButtonStr)
  ON_BN_CLICKED(IDC_BUTTON_STP, OnButtonStp)
  ON_WM_TIMER()    //追加
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

初歩的な間違いで申し訳ありませんでした.
相談に乗っていただきありがとうございました.

デッドロックに関してですが,どうしてデバッグに表示されたのか分からないうちに表示されなくなっていました.これもなぞではありますが.


黒々  2008-10-16 03:53:29  No: 69093

解決したようですが、一応。
メッセージを追加してなかったようですが、ひょっとして全部手入力でやっているのですか?
VCを使っているかは不明ですが、
VCに任せて(ClassWizard or イベントハンドラの追加)みては?
やり方はヘルプや参考書を見てください。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加