質問

VB.NET 2010、.NET 4

こんにちは皆さん、

System.timers.timerオブジェクトがあり、その経過イベントでいくつかの作業を行います。

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    '...work...
    MasterTimer.Enabled = True
End Sub

私の問題は、それがしている仕事が時々動かなくなるということです。作業の一部はシリアルコミュニケーションであるため、何かからの応答を待っているのを待っている可能性があります。私はすでに問題を解決するために私のシリアル通信コードを少し変更しました。ただし、このタイマーは基本的に生産制御アプリケーションの鼓動であり、何らかの理由で停止する場合は非常に悪いことです。 「作業」が時間がかかりすぎると、タイマーがそれ自体を再度再生できるようにして再試行できるように、フェイルセーフタイムアウトを入れるといいと思っていました。私はこのようなことを考えていました:

作業をサブルーチンに移動し、デリゲートを作成します。

Private Delegate Sub WorkDelegate()
Private Sub Work()
   '...work...
End Sub

デリゲートを呼び出して作業に電話してから、iasyncresultでWaitone(Timeout)を使用してタイムアウトを指定します。

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    Dim workDel as New WorkDelegate(AddressOf Work)
    Dim result as IAsyncResult = workDel.BeginInvoke
    result.AsyncWaitHandle.WaitOne(CInt(MasterTimer.Interval))
    MasterTimer.Enabled = True
End Sub

しかし、私の質問は次のとおりです。これは、work()が本当にどこかに立ち往生している場合に問題を引き起こすでしょうか?それはすでに実行されているサブルーチンに再び入るということですか?タイムアウト後に終了していない場合、作業()を中止する方法はありますか?言い換えれば、result.iscompletedがwaitoneの後にfalseである場合、作業()の実行を停止するだけですか?

私はこのことをあまりよく理解していないので、コメントは大歓迎です。おそらく、私が知らないこれにアプローチするまったく別の方法がありますか?

よろしくお願いします!

何かを追加したい:

ハンスの提案に従っていくつかの書き直しをするつもりですが、このエラーの原因を分離しようとするために、すでにテストの1日をスケジュールしていました。これまでのところ、コンパイルされたアプリケーションを実行するときにのみ発生しています。私は今日(そして昨日)、デバッグモードで実行中にフリーズを再現しようとして費やしました。これまでのところ、プログラムはデバッグモードで凍結していません。これを説明するかもしれないデバッグ環境について何か違うものがあるのではないかと思っています。それは私が「幸運」であるということかもしれませんが、おそらく実行可能ファイルを実行するときにプログラムが凍結した平均時間の3倍の時間をおそらく実行しています...繰り返しますが、私はかなり無知ですが、何でもありますかこれを説明できるデバッグ環境についてユニーク?フリーズしたらもう一度更新します。

役に立ちましたか?

解決

これは、コードの最初の行で問題が発生します。 System.timers.timerクラスはかなりickyです。コールstop()が別の呼び出しを防ぐという保証はまったくありません。タイマーはThreadPool.QueueUserWorkItemを使用して、Elapsed Event Handler Callを呼び出します。 ThreadPoolが忙しい場合、これはいくつかの電話をかけて、TPスケジューラからのゴーアードを実行して実行を開始するのを待っている可能性があります。タイマーを停止しても、待機中のスレッドが実行されないようにしません。ロックを使用せずに、これらのスレッドはお互いにひどく踏み込み、コミュニケーション状態を台無しにします。

安全なものはsystem.threading.timerです。変更()メソッドでタイマーを充電します。

DelegateのBeginInvoke()メソッドを呼び出してから、完了してブロックすることは意味がありません。 Invoke()を呼び出すだけです。別のスレッドを燃やすことからあなたを救います。

はい、「作業」メソッドが返さない場合、問題があります。解決できないもの。

この悲惨さの多くは、投票を使用してシリアルポートに何かが利用できるかどうかを確認することを避けた場合に消える可能性があります。価値のある何かが起こっていることを教えてください。受信バッファーに少なくとも1つのバイトがあるときはいつでも、スレッドプールスレッドでデータセレブスイベントを提起します。 WriteTimeOutプロパティを使用することは、通信プロトコルやデバイスに何かがおかしいときに立ち往生することを避けるための優れた方法でもあります。 1つのスレッドを捧げ、ブロッキング読み取りコールを作成することもうまく機能します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top