- PR -

2つのタイマー処理で、画面が応答なしになる

投稿者投稿内容
NEO
大ベテラン
会議室デビュー日: 2005/10/02
投稿数: 104
投稿日時: 2007-03-02 00:33
Threading.Timerクラスを使って定期的に画面表示をするアプリを作っています。

まず、メインフォームが2秒ごとに画面表示を行い、メインフォームにつけているボタンを押すことで表示されるモードレスダイアログでも2秒ごとに画面表示を更新します。

モードレスダイアログには閉じるためのボタンをつけているのですが、ボタンを押しても反応がありません。
それどころか、メインフォームも固まっているかのように白くなります。
解決したいのですが、原因が分からないので困っています。
インターバル2秒くらいのタイマーを2つ使ったくらいで、ビジーになるとは思えないんですが・・・。
何が原因と考えられるでしょうか?

気になるのは、メインフォームでインスタンス化したクラスをダイアログでも使ってることです。
2つの画面で、このクラスのメソッド内で生成されたデータをもらっています。
よねKEN
ぬし
会議室デビュー日: 2003/08/23
投稿数: 472
投稿日時: 2007-03-02 09:31
引用:

NEOさんの書き込み (2007-03-02 00:33) より:
Threading.Timerクラスを使って定期的に画面表示をするアプリを作っています。



画面と関連する使い方でタイマーを使うのに
System.Windows.Forms.Timerを使わない理由は何でしょうか?
(明確な理由があるのであれば別ですが、特に理由がなければWindows.Formsのタイマーを使う方がよいと思います)
IT:.NET Tips タイマにより一定時間間隔で処理を行うには?(Windowsタイマ編)

Threading.Timerを使うのであれば、UIスレッドとの同期を取る必要があるのですが、
以下のあたりを把握できているか確認してください。
IT:.NET Tips Windowsフォームで別スレッドからコントロールを操作するには?

上記のコメントはあやしそうかな?と思っただけで、解決策に結びつくかどうかはわかりません。
ご提示いただいている情報では、具体的な実現方法の大部分がわからないので、
アドバイスが非常に難しいです。

小さいプロジェクトを作成して、同じ現象を再現させようとしてみてください。
あるいは、今現在のソースコードを部分的にコメントアウトするなどして、
現象が起きる最小限のコードを見極めてください。

その最小限のコードを提示していただくのが最も手っ取り早いと思います。
#まぁその解析の過程で解決してしまう可能性の方が大きいですが。
NEO
大ベテラン
会議室デビュー日: 2005/10/02
投稿数: 104
投稿日時: 2007-03-03 12:11
引用:

よねKENさんの書き込み (2007-03-02 09:31) より:

画面と関連する使い方でタイマーを使うのに
System.Windows.Forms.Timerを使わない理由は何でしょうか?
(明確な理由があるのであれば別ですが、特に理由がなければWindows.Formsのタイマーを使う方がよいと思います)



インターバルを変える機能がありますので、短いインターバルが指定された場合でも対応できるようにするためです。

引用:

Threading.Timerを使うのであれば、UIスレッドとの同期を取る必要があるのですが、
以下のあたりを把握できているか確認してください。
IT:.NET Tips Windowsフォームで別スレッドからコントロールを操作するには?



ちゃんとできています。

引用:

小さいプロジェクトを作成して、同じ現象を再現させようとしてみてください。
あるいは、今現在のソースコードを部分的にコメントアウトするなどして、
現象が起きる最小限のコードを見極めてください。



問題のアプリとまったく同じコードではないですが、似たようなコードを組んでみても
ビジーになるようなことはありませんでした。
以下にコードを示します。

親フォーム
コード:
    Private timer As System.Threading.Timer
    Private t As Double = 0

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim timerDelegate As System.Threading.TimerCallback _
         = New System.Threading.TimerCallback(AddressOf worker)
        timer = New System.Threading.Timer(timerDelegate, Nothing, 0, 500)
    End Sub

    Delegate Sub DelegateFuc()

    Private Sub worker(ByVal o As Object)
        Invoke(New DelegateFuc(AddressOf UpdateText))
    End Sub

    Private Sub UpdateText()
        Dim r As New Random

        t = r.NextDouble
        TextBox1.Text = t.ToString("#0.00")
        Debug.Print(String.Format("{0} (2)...", Now.ToString("yyyy/MM/dd HH:mm:ss.fff")))
    End Sub



モードレスダイアログ
コード:
   Private timer As System.Threading.Timer

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim timerDelegate As System.Threading.TimerCallback _
         = New System.Threading.TimerCallback(AddressOf worker)
        timer = New System.Threading.Timer(timerDelegate, Nothing, 0, 1000)
    End Sub

    Delegate Sub DelegateFuc()

    Private Sub worker(ByVal o As Object)
        Invoke(New DelegateFuc(AddressOf DisplayText))
    End Sub

    Private Sub DisplayText()
        Dim r As New Random
        Dim t As Double

        For ix As Integer = 0 To 10000 - 1
            t += r.NextDouble
        Next

        TextBox1.Text = (t / 10000).ToString("#0.00")
    End Sub



上記コードでは足し算とか乱数の表示のみですが、
実際のアプリでは、親とダイアログで同じインスタンスからデータをもらっています。
もらうデータの件数は1〜数千件です。
データをもらうメソッドは異なりますが、やはりそのメソッドの処理が影響しているのでしょうか?
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2007-03-04 00:21
引用:

NEOさんの書き込み (2007-03-03 12:11) より:

上記コードでは足し算とか乱数の表示のみですが、
実際のアプリでは、親とダイアログで同じインスタンスからデータをもらっています。
もらうデータの件数は1〜数千件です。
データをもらうメソッドは異なりますが、やはりそのメソッドの処理が影響しているのでしょうか?


このデータをもらって何らかの処理してるのはコールバック側でしょうか?
それとも画面更新側でしょうか?あるいは両方でしょうか?

このデータのアクセス(処理)は何らかの方法で同期しているでしょうか?
あるいはそれぞれのメソッドで同期は取らずに処理しているでしょうか?

データの処理あるいは画面への表示?処理は2秒よりずっと短い時間しかかからない処理でしょうか?
結構時間がかかる処理でしょうか?
場合によっては2秒以上かかることもあるというくらいの処理でしょうか?

タイマーでの処理と画面表示の処理は、例のコードのように順に1回ずつだけでしょうか?
あるいはレコードごとなど、処理と表示を繰り返す感じでしょうか?
NEO
大ベテラン
会議室デビュー日: 2005/10/02
投稿数: 104
投稿日時: 2007-03-04 00:37
引用:

なちゃさんの書き込み (2007-03-04 00:21) より:

このデータをもらって何らかの処理してるのはコールバック側でしょうか?
それとも画面更新側でしょうか?あるいは両方でしょうか?



コールバック側???
記事に載せたコードで言うと、UpdateTextメソッドやDisplayTextメソッドにあたります。

引用:

このデータのアクセス(処理)は何らかの方法で同期しているでしょうか?
あるいはそれぞれのメソッドで同期は取らずに処理しているでしょうか?



同期はとっていません。

引用:

データの処理あるいは画面への表示?処理は2秒よりずっと短い時間しかかからない処理でしょうか?
結構時間がかかる処理でしょうか?
場合によっては2秒以上かかることもあるというくらいの処理でしょうか?



親とダイアログから呼ばれるメソッドでは、複雑な計算を行っています。
その数は50くらいです。
計算の対象となるデータの件数は多くても数千件です。
2秒はかからないと思うのですが…。

引用:

タイマーでの処理と画面表示の処理は、例のコードのように順に1回ずつだけでしょうか?
あるいはレコードごとなど、処理と表示を繰り返す感じでしょうか?



親、ダイアログ共にタイマーで、データをもらう→画面表示更新 となっています。
べる
ぬし
会議室デビュー日: 2003/09/20
投稿数: 1093
投稿日時: 2007-03-04 02:34
引用:
インターバルを変える機能がありますので、短いインターバルが指定された場合でも対応できるようにするためです。

System.Windows.Forms.Timerでもミリ秒単位でインターバルが指定できますよ?
System.Windows.Forms.Timerに置き換えてみましたか?System.Windows.Forms.Timerは
「フォーム アプリケーションで使用できるように最適化」されているので、これを使ったら
問題が解決される可能性もなくはないです。

引用:
問題のアプリとまったく同じコードではないですが、似たようなコードを組んでみても
ビジーになるようなことはありませんでした。
以下にコードを示します。

これでビジーにならなかったんだから「同じでない」その部分が原因ということになりますよね。
というか、「問題の現象が再現する」最小のコードを示すべきでは?

引用:
親とダイアログから呼ばれるメソッドでは、複雑な計算を行っています。
その数は50くらいです。
計算の対象となるデータの件数は多くても数千件です。
2秒はかからないと思うのですが…。

どんな計算を行っているかわからないので2秒かかるかどうかもわかりません。
というか、その部分だけ切り出して、計測してみればいいのでは?
NEO
大ベテラン
会議室デビュー日: 2005/10/02
投稿数: 104
投稿日時: 2007-03-06 00:13
親とダイアログそれぞれの処理がどのような順序で実行されているかログに出してみました。

どうやら定期的に動いていないようです。

(1) 親フォームの処理
(2) ダイアログの処理
(3) 親フォームの処理
(4) 親フォームの処理
(5) ダイアログの処理
(6) 親フォームの処理
(7) 親フォームの処理


こんな感じでした。
親フォームのタイマーインターバルはダイアログのタイマーインターバルの半分であるにもかかわらずです。
ダイアログの処理が完了するまでに4秒かかっていました。
その間、親フォームには制御が渡っていません。
そして、ダイアログ側の処理が終わった(?)ら、親フォームの処理が続けて実行されました。

ダイアログ側のタイマーで呼ばれるメソッドには、いろいろコードを書いてますが、
それらのコード自体には時間がかかっていないみたいでした。(ログで確認)
しかし、ダイアログ側のメソッドに入った直後とメソッドを出る直前の経過時間が約4秒なんです。
ダイアログ側のメソッドを出る直前では、PanelのRefreshをしているだけなんですけどね。
まさかこれが原因・・・?
ちなみに、ダイアログ側のタイマーをThreading.TimerクラスからForms.Timerクラスに変えても同じでした。

べる
ぬし
会議室デビュー日: 2003/09/20
投稿数: 1093
投稿日時: 2007-03-06 02:39
引用:
ダイアログ側のメソッドを出る直前では、PanelのRefreshをしているだけなんですけどね。
まさかこれが原因・・・?

原因かどうかは、そのコードをはずして確認してみればいいんじゃないですか?

別スレッドからPanelを直接操作した場合の動作は保障されませんよ。
ぁ、でもそれは「ちゃんとできています。 」なんでした。。

やはり、同じインスタンスからデータを云々、ていうのが原因なんでしょうかね。

スキルアップ/キャリアアップ(JOB@IT)