【问题标题】:Sleeping/waiting for a long time睡觉/等待很长时间
【发布时间】:2015-06-28 11:01:08
【问题描述】:

我正在用 C# 设计一个工业硬件控制程序,它将通过串行端口一次运行 72 小时。

在伪代码中,我想要做的是这样的:-

while(true) {
    TalkToSerialPort1();
    WaitForXHours(3);
    TalkToSerialPort2();
    WaitForXHours(1);
    // etc
}

我将此代码放在与我的主控制台或 GUI 程序不同的线程中,并且必须按程序运行

似乎Thread.Sleep() 很长一段时间似乎毁了我的一天!我正在寻找一种可靠的长时间睡眠方式。

任何信息都会有所帮助。

【问题讨论】:

  • 我认为您不应该使用 Sleep() 方法。而是使用 WaitHandle 同步线程。
  • 在 72 小时结束时,程序是完成还是要重复?如果程序崩溃会发生什么?它是否需要在失败时重新启动?有很多方法可以构建它。
  • 为什么这对你不起作用?它应该。当然你会有时间偏差,因为 TalkToSerialPort1 需要一些时间。

标签: c# .net multithreading


【解决方案1】:

Stopwatch 是解决此问题的更好方法**。例如:

    Stopwatch spw = new Stopwatch();            

    int stepNo = 0;
    while (!haltWork)
    {
        Thread.Sleep(100);
        switch (stepNo)
        {
            case 0:
                TalkToSerialPort1();
                spw.Restart();
                stepNo += 1;
                break;
            case 1:
                if (spw.Elapsed.Hours >= 3)
                {
                    TalkToSerialPort2();
                    spw.Restart();
                    stepNo += 1;
                }
                break;
            case 2:
                if (spw.Elapsed.Hours >= 1)
                {
                    TalkToSerialPort3();
                    spw.Restart();
                    stepNo += 1;
                }
                break;
            // etc...

        }
    }

在这里我添加了一个条件haltWork - 如果需要,您的主程序将需要某种方式来通知该线程及时退出。这将在轮询循环中运行线程,允许它中断和退出,支持用户取消,并且由于秒表,将在用户取消的情况下为您提供当前步骤经过的精确时间,您可以使用进程诊断、重启程序等。

使用switch 语句将程序过程分解为多个步骤。这使您可以以干净和合乎逻辑的方式执行长时间运行的程序过程,等待或轮询步骤,同时保持响应,能够提供主动反馈(考虑定期引发事件以提醒主线程当前步骤、已用时间等,例如进程日志记录目的)。

另请注意,此示例在每一步都会重置秒表 - 您如何执行此操作取决于您的要求;您是否需要控制步骤之间的间隔,或者对于任意参考保持规律的步伐是否更重要。如果是后者,自然只需启动秒表一次,然后将其余时间间隔设为绝对而不是相对。


** 我的假设是在您的 C# 应用程序中执行此操作已经过仔细考虑,并且这是负责此任务的最佳位置。

Windows 任务调度程序是处理需要长时间运行的重复性“无头”任务的另一种选择。

另一种选择,特别是与工业控制相关,是使用专用硬件来执行此操作 - 小型 PLC 等。

【讨论】:

    【解决方案2】:

    您应该使用 Quartz .NET,它是可靠且非常准确的调度程序。 在这里阅读更多:https://www.quartz-scheduler.net/

    【讨论】:

      【解决方案3】:

      另一种方法是使用计时器

      例如calling method on every x minutes

      注意:在这种情况下 - 在开始新的操作之前,您必须确保之前的操作已经完成。

      【讨论】:

        【解决方案4】:

        好吧 - 如果你想坚持"while (true)" 模式, 你能做的就是这样:

        while (true){
        
        if (DateTime.Now - LastExecutionDate > 72h)
        {
           doYourStuff();
           Update_LastExecutionDate;
        }
        else{
          continue; //or sleep for 5 minutes
        }
        

        【讨论】:

        • DateTime 是我解决这个问题的方法,它解决了它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-12
        • 2013-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-25
        • 1970-01-01
        相关资源
        最近更新 更多