Timerイベントのフリーズ対策は?


浩二  2005-10-04 03:49:49  No: 125972

Timerイベントでinterval10000とした場合、
10秒後にTimerイベントが開始されますが、
その際にフォームを移動などした場合フリーズといいますか、
フォームが移動付加になります。
(Timerイベントが終了すると復帰しますが・・)

Timerイベントに長い処理を書く場合長時間フリーズのようになってしまいます。
Doeventsでどうにかなるかと試してみましたがどこに入れてもフリーズ状態です。
対策をご存知の方ご教示いただけませんでしょうか。


030  2005-10-04 05:24:08  No: 125973

どこで時間がかかっているかぐらいは分かるんじゃないですか?
おそらく何かの同期的な動作をする関数もしくはAPIで止まってるような気もしますが。
まずは何で止まってるのかを見つけてください。
>おそらく何かの同期的な動作をする関数もしくはAPIで止まってるような気もしますが。
でなければDoEventsで回避できるはずです。
であれば、あきらめましょう。
もしくは.Netならマルチスレッドを使うかVB6なら別プロセスに処理させるとか。


浩二  2005-10-04 05:59:47  No: 125974

別プロセスで処理させるためにはどのようにしたらいいのでしょうか?
検索しても別プロセスの制御ばかりでてしまい、
別プロセスで処理させる方法がHITしません・・・


030  2005-10-04 07:09:45  No: 125975

まずは何で止まってるのかを見つけてください。


浩二  2005-10-04 07:23:57  No: 125976

なんでも固まるみたいですが・・・
>(Timerイベントが終了すると復帰しますが・・)
終了後は移動可能となります。

Private Sub Command1_Click()
    Me.Timer1.Interval = 1000
End Sub

Private Sub Timer1_Timer()
    Dim I As Integer
    
    For I = 1 To 10000
        DoEvents
        Me.List1.AddItem I
    Next
End Sub

コマンド1をクリック

フォームをドラッグし移動させる

フォームがフリーズ状態になる

処理終了後は正常にもどる


  2005-10-04 08:03:30  No: 125977

横入り失礼します。

Timerイベントの意味を把握しないと、思わぬところで苦戦します。
再度ご確認下さい。

>For I = 1 To 10000
>    DoEvents
>    Me.List1.AddItem I
>Next

Timerイベントは、「Intervalで設定した間隔ごとに発生」します。

>Private Sub Command1_Click()
>    Me.Timer1.Interval = 1000
>End Sub
つまり、
「1秒間の間に10000回ループを起こして、10000個の数値をリストに追加する」
という処理をしている事になります。
(フォームを移動させなくてもフリーズするような気がしますが…。)


030  2005-10-04 08:12:23  No: 125978

同じコードで試してみましたが特にフリーズする状態にはなりませんでした。
環境は何ですか?


浩二  2005-10-04 10:24:24  No: 125979

>「1秒間の間に10000回ループを起こして、10000個の数値をリストに追加する」
>という処理をしている事になります。
100も承知ですが・・
重い処理を考えたのでこのコードとしました。
重ければ別になんでもいいんです。
intervalの期間も関係ありません。

>コマンド1をクリック
>↓
>フォームをドラッグし移動させる
>↓
>フォームがフリーズ状態になる
>↓
>処理終了後は正常にもどる

コマンド1をクリック後1秒以内にフォームを移動させます。
>10秒後にTimerイベントが開始されますが、
>その際にフォームを移動などした場合
の通りです。
移動させている途中でタイマーイベントが開始されると現象が発生するといえば通じるでしょうか。
本題はフリーズではなくフォームが移動できなくなる現象です。
環境はVB6.0WinXPproSP2


コボル  2005-10-04 18:04:20  No: 125980

重たい処理を流せば、フォームの動きも悪くなるのでは?


浩二  2005-10-04 19:36:25  No: 125981

動きが悪くなるだけなら構いませんが全く動かなくなります。
文で説明するのは難しいので試してみていただけると助かるのですが・・。


特攻隊長まるるう  2005-10-04 20:09:22  No: 125982

実行環境にもよるでしょうが、提示されたサンプルでは DoEvents が
しっかり機能できますし、1つの処理が終わる前にもう一度別の処理が
呼ばれた時に、何も考えずその処理を受けるという設計段階の問題点
となります。たとえ別プロセス等を考えたとしても、際限なく命令を
受ければいつか処理できなくなって当然ですから、原因を確定してから
対策を考えて下さい。


特攻隊長まるるう  2005-10-04 20:13:48  No: 125983

…というか
>移動させている途中でタイマーイベントが開始されると現象が発生するといえば通じるでしょうか。
これ↑が原因なのは確定してるのでしょうか?…失礼しました。
際限なく命令を受けるのは不可能ですから、そこはどう考えているのでしょうか?
1つ処理が走っていれば、フラグを立てておき、次の処理を行わないのが
通常の考え方かと思いますが。


名無し  2005-10-04 20:32:08  No: 125984

>重い処理を考えたのでこのコードとしました。
>重ければ別になんでもいいんです。

意図がわからない。
それなら、重くなる=他の処理ができなくなる=フリーズ、だろうからやりたい事ができてると思われ。

ウエイトを入れたい訳ではあるまいし…なにがしたいのか。


特攻隊長まるるう  2005-10-04 20:36:48  No: 125985

ちなみに
>移動させている途中でタイマーイベントが開始されると現象が発生するといえば通じるでしょうか。
という現象は再現できませんでした。以下コードで確かめましたが、
2回目以降のタイマーイベントの処理は1回目のイベント内のループ
処理が終了するまで実行されませんでした。
030 さんの書き込み通り
>同じコードで試してみましたが特にフリーズする状態にはなりませんでした。
そういった意味でも原因を調べてもらわないといけませんね。
[VB6.0]
Option Explicit
Private LoopCount As Long
Private Sub Command1_Click()
    Me.Timer1.Interval = 100
    LoopCount = 0
End Sub
Private Sub Command2_Click()
    Me.Timer1.Interval = 0
End Sub
Private Sub Timer1_Timer()
    Dim I As Integer
    LoopCount = LoopCount + 1
    Debug.Print LoopCount
    For I = 1 To 10000
        DoEvents
        Me.List1.AddItem I
        Me.Label1.Caption = I
    Next
End Sub


浩二  2005-10-04 20:51:57  No: 125986

>特攻さん
Me.Timer1.Interval = 100
これだとコマンド1を押した後に0.1秒以内にフォームを移動させると正常に動きますね。
私が説明しているのはフォームを移動させているときにTimerイベントが実行された場合の現象です。
Intervalを3000にしコマンド1をクリック、フォームをTimerイベントが開始されるまで動かし続ける。
これで必ず同じ現象がおこるはずです。

>名無し
>意図がわからない。
>それなら、重くなる=他の処理ができなくなる=フリーズ、だろうからやり>たい事ができてると思われ。
>
>ウエイトを入れたい訳ではあるまいし…なにがしたいのか。
別に固めたいわけじゃない。
むしろ固めたくないが故の質問だ。
Timerイベントが開始された後にフォームを移動させる事はできる。
フォームを移動させているときにTimerイベントが発生すると固まる。
(処理が固まるわけではない。フォームの移動が出来なくなる。)


浩二  2005-10-04 20:53:47  No: 125987

タイプミスです。

>>特攻さん
>Me.Timer1.Interval = 100
>これだとコマンド1を押した後に0.1秒以内にフォームを移動させ続けていない限り正常に動きます。

に訂正します。


特攻隊長まるるう  2005-10-04 21:16:53  No: 125988

>Intervalを3000にしコマンド1をクリック、フォームをTimerイベントが開始されるまで動かし続ける。
>これで必ず同じ現象がおこるはずです。
フォームを動かした時点でループ処理が止まるから、タイマーイベント
が起こりません。他に条件は?。


もげ  2005-10-04 22:24:44  No: 125989

>>Intervalを3000にしコマンド1をクリック、フォームをTimerイベントが開始されるまで動かし続ける。

Intervalを3000にした場合、
コマンド1をクリックして、直ちにマウスでフォームのタイトルバー部分をつかみ、
そのまま3秒以上ドラッグしつづけると、
Timerイベントが始まったとたんに、フォームがドラッグに追従しなくなる
という現象を問題にしている。

という理解で合っていますか?


名無し  2005-10-04 22:44:09  No: 125990

だったらフォームをドラッグしてる時にはTimerのイベントを発動させなければいいんじゃない?知らんけど。


ひでらん  2005-10-04 23:37:59  No: 125991

Timerイベントの中に重たい処理を書くから
駄目なんじゃないですか?
割込み処理が終了しないし・・・。


ガッ  2005-10-04 23:56:55  No: 125992

おー、なるなる!
こんな使い方初めてだなー…

で、ウィンドウイベント関連の現象なので、
サブクラス化してメッセージの流れなどをつかむ必要があるかもしれません。
色々面倒なので、「イベントプロシージャの中でDoEventsを使わない」処理にしてみてはどうでしょう?


浩二  2005-10-05 04:25:47  No: 125993

>特攻さん
>>Intervalを3000にしコマンド1をクリック、フォームをTimerイベントが開>>始されるまで動かし続ける。
>>これで必ず同じ現象がおこるはずです。
>フォームを動かした時点でループ処理が止まるから、タイマーイベント
>が起こりません。他に条件は?。

>>特攻さん
>Me.Timer1.Interval = 100
>これだとコマンド1を押した後に0.1秒以内にフォームを移動させると正常に>動きますね。
>私が説明しているのはフォームを移動させているときにTimerイベントが実行された場合の現象です。
>Intervalを3000にしコマンド1をクリック、フォームをTimerイベントが開始>されるまで動かし続ける。
>これで必ず同じ現象がおこるはずです。
>-------------------------------------------------------
>タイプミスです。
>
>>特攻さん
>Me.Timer1.Interval = 100
>これだとコマンド1を押した後に0.1秒以内にフォームを移動させ続けていな>い限り正常に動きます。
>
>に訂正します。
このレスを読んでください。

>もげさん
仰るとおりです。

>ガッさん
DoEventsを使わないとフリーズ、DoEventsを使うとフォームがフリーズ・・・。
サブクラス化について調べてみます。


我龍院忠太  2005-10-05 17:26:18  No: 125994

えー、再現法は簡単、Listで無くてもLabelでもなる、
Private Sub Command1_Click()
    Me.Timer1.Interval = 2000
    Timer1.Enabled = True
End Sub
Private Sub Timer1_Timer()
    Dim I As Integer
    For I = 1 To 10000
        DoEvents
        Label1.Caption = "" & I
    Next
End Sub
とラベルを一つ追加して、ラベルの表示が1000になった時次のタイマーが
ONになるまでフォームを動かすと、タイマーがONになったとたんに
フォームのゴーストが出たまま、DoEventsを受け付けなくなるり、次の
タイマーがONになるまで、フリーズ状態になる、ただしラベルは更新しつづける。

通常フォームを動かすと(タスクバーをクリックすると)、そのスレッドの動作は
止まるのだけれど、Timerだけは動いていて、割り込みがかかりTimerの中に
書かれた処理をし始める、そのときはDoEventsは受け付けない。
処理が重い軽いは関係ない、なんと無くTimerのBの字のような気がする。


K.J.K.  2005-10-05 18:01:48  No: 125995

Timerイベントプロシージャ中の先頭で、TimerのEnabledをFalseにし、
(もし続ける必要があれば)イベントプロシージャから抜ける直前で、
TimerのEnabledをTrueにするとか。
# そもそもWM_TIMERの仕様から考えて仕方が無いところでしょう。

ウィンドウを動かす、ウィンドウのタイトル上でマウス右ボタンを
押したままにする、という条件下でも更新を続けるサンプルを以前
作りましたが、このケースではあまり参考にはならないでしょう。
http://www.koalanet.ne.jp/~akiya/vbtaste/vbp/StpWch20.lzh


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

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






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