【问题标题】:C# timer Which timer I should use?C# timer 我应该使用哪个定时器?
【发布时间】:2016-09-30 10:59:50
【问题描述】:

我正在编写一个程序,它从串行端口读取每秒数据并将其保存在文本文件中/在 GUI 上显示。阅读以单击按钮开始和结束。

我尝试了一些不同的计时器来解决这个问题,但每个计时器都会带来一些麻烦(见下文)。

我的试训:

serialPort1.ReadTimeout = 2000;

System.Timers.Timer:

    private void timer1_Tick(object sender, EventArgs e) 
    {
        if (!serialPort1.isOpen) 
        {
            serialPort1.Open();
        }

        serialPort1.WriteLine("INFO"); //Send data command
        string data = serialPort1.ReadLine();

        serialPort.Close();
        editData(data); //Method for GUI update and textfile log
    }

可以使用 timer1.Start() 和 timer1.Stop() 轻松启动和停止。问题是,System.Timers.Timer 在 GUI Thrard 上运行并在调用 serialPort.read 和 serialPort.Close() 时冻结 GUI。


后台工作人员:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        while (backgroundWorker1.CancellationPending == false)
        {
            if (!serialPort1.isOpen)
            {
                serialPort1.Open();
            }

            serialPort1.WriteLine("INFO");
            string data = serialPort1.ReadLine();

            serialPort.Close();
            Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
        }
    }  

异步运行。我需要每秒运行一次程序。


System.Timers.Timer 调用 Backgroundworker:

    private void timer1_Tick(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
            if (!serialPort1.isOpen)
            {
                serialPort1.Open();
            }

            serialPort1.WriteLine("INFO");
            string data = serialPort1.ReadLine();

            serialPort.Close();
            Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
    }  

在数据读取过程需要更长的时间或发生 serialPort.readTimeout 之前,这可以正常工作。 Backgroundworker 只能运行一次。所以我认为这不是一个选择。


System.Threading.Timers:

        System.Threading.Timer timer;
        timer = new System.Threading.Timer(_ => readSerialPort(), null, 0, 950);

        private void readSerialPort()
        {
            if (!serialPort1.isOpen)
            {
                serialPort1.Open();
            }

            serialPort1.WriteLine("INFO");
            string data = serialPort1.ReadLine();

            serialPort.Close();
            Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
        }

这很好,但问题是,我无法停止并重新开始阅读。


有人知道在这种情况下我应该使用哪个计时器吗?

【问题讨论】:

  • 好吧,你已经概述了你的选择,并为每一个添加了推理。您到底期望什么作为答案? :)
  • System.Timers.Timer 默认不在 UI 线程上运行,只有在你设置了 SynchronizingObject 时才运行。
  • @Luaan 我正在寻找一个选项,我可以在其中启动和停止数据读取,并且在 serialPort.Close()、/SerialPort.ReadLine() 时 GUI 不应该冻结
  • 另一种选择是不使用任何计时器,而是使用一个简单的后台线程来处理启动/停止并进行适当的循环以定期从端口读取。
  • 您可以停止并重新启动System.Threading.Timer - 只需使用Timer.Change()。因此,我建议您使用此计时器。

标签: c# multithreading timer


【解决方案1】:

关于System.Threading.Timer

var timer = new System.Threading.Timer(cb, null, 1000, 1000); // init   
timer.Change(Timeout.Infinite, Timeout.Infinite); // stop   
timer.Change(0, 1000); // start

附:不要忘记配置计时器

【讨论】:

    【解决方案2】:

    您可以使用线程来实现此逻辑。元代码如下:

            var stopEvent = new ManualResetEvent(false);
            var thread = new Thread(() => {
    
                if (!serialPort1.isOpen)
                {
                    serialPort1.Open();
                }
                try
                {
    
                    while (!stopEvent.WaitOne(0))
                    {
                        try
                        {
                            serialPort1.WriteLine("INFO");
                            string data = serialPort1.ReadLine();
                            Invoke((MethodInvoker)(() => editData(data)));
    
                        }
                        catch (Exception)
                        {
    
                            // Handle exception, e.g. a reading timeout
                        }
    
                        stopEvent.WaitOne(1000); //Thread.Sleep(1000);
                    }
                } finally
                {
                    serialPort.Close();
                }
    
    
            });
            thread.Start();
    
            //call it to stop the loop.
            stopEvent.Set();
        }
    

    您可以实现更复杂的逻辑,例如停止和恢复读数。只需使用更多事件。如果您不熟悉事件,您可以只使用布尔变量,但将它们定义为volatile。

    【讨论】:

    • 这是一个在没有计时器的情况下工作的好主意。我试试,谢谢
    猜你喜欢
    • 2012-11-23
    • 2018-12-03
    • 1970-01-01
    • 2011-11-06
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多