【问题标题】:Stop execution of code in x minutes在 x 分钟内停止执行代码
【发布时间】:2015-01-29 13:43:41
【问题描述】:

我有一个应用程序,其中命令以 x 分钟的间隔发送到串行端口。代码:

int i = 0;

do
{
      // Send temperature
      com.SendComMessage(Temperature[i], Command[i]);

       // Start timer
       System.Timers.Timer t = new System.Timers.Timer();
       t.Elapsed += new TimerElapsedEventHandler();
       t.Interval = Convert.ToInt32(Time[i]);
       t.AutoReset = false;
       t.Enabled = true;

        // Tell CarbageCollector not to destroy the timer
        GC.KeepAlive(t);

        i++;

} while (i <= count);

我想在时间过去之前停止执行循环。

我考虑过使用线程,像这样:

System.Threading.Thread.Sleep(Convert.ToInt32(Time[i])*60);

但我可能不会在代码休眠时更新 GUI,因为串行端口接收来自设备的响应。

我怎样才能做到这一点?

【问题讨论】:

  • 是计时器来查看您是否在 X 秒内没有收到回复?...或者您只是想要在您发送的命令之间有延迟?
  • @Idle_Mind 只是命令之间的延迟。

标签: c# multithreading timer


【解决方案1】:

那么 Steven Rands 已经使用 async/await 和 Task.Delay() 给了你一个很好的答案:

private async void button1_Click(object sender, EventArgs e)
{
    int i = 0;
    do
    {
        // Send temperature
        com.SendComMessage(Temperature[i], Command[i]);
        await Task.Delay(1000); // wait one second before continuing
        i++;
    } while (i <= count);
}

请注意,该方法已用async 标记,我们正在await 调用Task.Delay()。这将导致响应式 GUI 在继续循环的下一次迭代之前等待一秒钟时仍然可以接收事件。

如果您需要将超时期限与成功/失败类型的场景结合起来,那么请考虑这样的事情:

    private System.Threading.ManualResetEvent MRE = new System.Threading.ManualResetEvent(false);

    private async void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;

        bool result = false;
        for (int i = 1; i <= 5; i++ )
        { 
            Console.WriteLine("Message " + i.ToString() + " Sent");

            MRE.Reset();
            await Task.Run(delegate()
            {
                result = MRE.WaitOne(TimeSpan.FromSeconds(10)); // wait up to ten seconds for MRE to be set
            });

            if (result)
            {
                Console.WriteLine("Success!");
            }
            else
            {
                Console.WriteLine("Timeout Fail");
            }
        }

        button1.Enabled = true;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        // simulated receipt of something
        Console.WriteLine("...bloop...");
        MRE.Set(); // tell the main loop it's okay to continue
    }

【讨论】:

    【解决方案2】:

    如果要更新 GUI,则需要在与 UI 不同的线程中运行串行端口通信代码。

    使用任务并行库(即Task 对象、asyncawait)或类似BackgroundWorker 的东西将通信代码转移到后台线程。

    在您的后台线程中,您将有效地拥有一个循环,该循环将命令发送到 COM 端口,然后对响应进行解码。在该循环中,您可以使用 Thread.Sleep(...)await Task.Delay(...) 在请求之间“暂停”。

    【讨论】:

      猜你喜欢
      • 2014-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-12
      • 2018-03-21
      • 1970-01-01
      相关资源
      最近更新 更多