15

背景: serialPort DataReceived イベントが発生してからの経過時間を追跡するために使用しているタイマーがあります。クエリを送信して 1 つの応答を取得する代わりに、データの連続ストリームを取得しているため、組み込みのタイムアウト イベントを使用する代わりに、これに対する独自のソリューションを作成しています。

問題: DataReceived ハンドラーには、タイマーが経過しないように停止するステートメントがあります。問題は、多くの場合、Elapsed ハンドラーのあとがきが実行されることです。

SynchronizingObject を使用してこの問題を解決できることを読みましたが、それを達成する方法がわかりません。

これが私のコードです。関連性がないと思われるものはすべて切り取ろうとしました。

    private System.Timers.Timer timeOut;
    private System.Timers.Timer updateTimer;

    public void start()
    {
        thread1 = new Thread(() => record());

        thread1.Start();
    }

    public void requestStop()
    {
        this.stop = true;
        this.WaitEventTest.Set();

    }

    private void record()
    {
        timeOut = new System.Timers.Timer(500); //** .5 Sec
        updateTimer = new System.Timers.Timer(500); //** .5 Sec

        timeOut.Elapsed += TimeOut_Elapsed;
        updateTimer.Elapsed += updateTimer_Elapsed;
        updateTimer.AutoReset = true;


        comport.Open();
        comport.DiscardInBuffer();


        comport.Write(COMMAND_CONTINUOUSMODE + "\r");

        stopwatch.Reset();
        stopwatch.Start();

        recordingStartTrigger(); //** Fire Recording Started Event

        timeOut.Start();
        updateTimer.Start();

        this.waitHandleTest.WaitOne(); //** wait for test to end

        timeOut.Stop();
        updateTimer.Stop();

        comport.Write(COMMAND_COMMANDMODE + Environment.NewLine);
        comport.DiscardInBuffer();
        comport.Close();
        recordingStopTrigger(status); //** Fire Recording Stopped Event

        stopwatch.Stop();
    }


    //***********************************************************************************
    //** Events Handlers


    private void comDataReceived_Handler(object sender, SerialDataReceivedEventArgs e)
    {

        double force = -100000;
        string temp = "-100000";

        //timeOut.SynchronizingObject.Invoke(new Action(()=> {timeOut.Stop();}), new object[] {sender, e});

        timeOut.Stop();

        //** I removed my action code here, keep things simple.


        timeOut.Start();
    }

    private void TimeOut_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        timeOut.Stop();
        updateTimer.Stop();


        //** fire delegate that GUI will be listening to, to update graph.
        if (eventComTimeOut != null && this.stop == false)
        {
            if (eventComTimeOut(this, new eventArgsComTimeOut(comport.PortName, "READ")))
            {
                //retry = true;
                comport.Write(COMMAND_CONTINUOUSMODE + "\r");
                updateTimer.Start();
                timeOut.Start();
            }
            else
            {
                this.stop = true;
                //retry = false;
                this.WaitEventTest.Set();
                status = eventArgsStopped.Status.failed;                     
            }
        }
    }

    void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {

        //** fire delegate that GUI will be listening to, to update graph.
        List<Reading> temp = new List<Reading>(report.Readings_Force);
        eventNewData(this, new eventArgsNewData(temp));

    }
4

3 に答える 3

33

これはよく知られた動作です。実行のためにSystem.Timers.Timer内部的に使用します。ThreadPoolランタイムはTimerスレッドプールでキューに入れます。メソッドを呼び出す前に、すでにキューに入れられていますStop。経過時間で発火します。

これを回避するTimer.AutoResetには、必要に応じて false に設定し、経過したハンドラーでタイマーを開始します。false を設定AutoResetすると、タイマーが 1 回だけ起動するため、タイマーを一定間隔で起動するには、タイマーを手動で再起動します。

yourTimer.AutoReset = false;

private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
     try
     {
         // add your logic here
     }
     finally
     {
         yourTimer.Enabled = true;// or yourTimer.Start();
     }
}
于 2013-08-16T19:14:51.040 に答える
2

このコードでタイマーを一時停止しました。私にとってはうまくいきます。

Private cTimer As New System.Timers.Timer
Private Sub inittimer()
    cTimer.AutoReset = True
    cTimer.Interval = 1000
    AddHandler cTimer.Elapsed, AddressOf cTimerTick
    cTimer.Enabled = True
End Sub

Private Sub cTimerTick()
    If cTimer.AutoReset = True Then
       'do your code if not paused by autoreset false
    End If
End Sub
于 2017-09-01T13:02:17.173 に答える