在Console Application中显示Thread.Sleep()的剩余时间

时间:2012-10-03 14:27:14

标签: c# .net timer console-application

我有一个无限运行的.net控制台应用程序。我已经插入了Thread.Sleep() 5分钟来暂停我的申请。 在这个时间点,我想显示用户剩余时间(以秒为单位)让线程变为活动状态并再次开始应用程序。

class Program
{
    static void Main(string[] args)
    {
        Program program = new Program();
        program.startFeed();
    }
    public void startFeed()
    {
        while (true)
        {
            try
            {
                //My Application which i want to run continously 
                //when thread enters in run mode
            }
            catch (Exception xObj)
            {
                Console.WriteLine(DateTime.Now.ToString() 
                    + " >> Incoming Message Processing Error. >> " 
                    + xObj.Message);
            }
            Console.WriteLine("Waiting For Data......");
            Thread.Sleep(300000);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您程序的当前结构不支持您要实现的目标。

当您致电Thread.Sleep(int)时,它会暂停当前线程达到指定时间。默认情况下,程序仅作为单个线程运行,因此挂起该线程会阻止所有代码运行。

您希望向用户显示更新,但您还希望工作进程在运行之间等待5分钟。这意味着您需要为工作进程创建一个单独的线程,并从程序开始的线程中管理它。

其中一种更简单的方法是使用System.Threading.Timer,正如其他人所建议的那样。在您的情况下,您可以将代码更改为以下内容:

class Program
{
    static void Main(string[] args)
    {
        Program program = new Program();
        program.startFeed();
    }

    // This is run on the main thread
    public void startFeed()
    {
        // Start a Timer on a new thread to do work with the ProcessData method
        // Pass null to its 'state' argument, wait 0 milliseconds before
        // running it, and run it once every 300000 milliseconds
        using (new Timer(ProcessData, null, 0, 300000))
        {
            // The Timer will only exist while we are inside the 'using' block;
            // stay here with a loop
            while (true)
            {
                // Write our status message
                Console.WriteLine("Waiting for data at {0}...", DateTime.Now);
                // We don't want this loop running ALL the time; add a small
                // delay so it only updates once every second
                Thread.Sleep(1000); 
            }
        }
    }

    // This is run on the background thread
    private void ProcessData(object state)
    {
        try
        {
            //My Application which i want to run continously 
            //when thread enters in run mode
        }
        catch (Exception xObj)
        {
            Console.WriteLine(DateTime.Now.ToString()
                + " >> Incoming Message Processing Error. >> "
                + xObj.Message);
        }
    }
}

很好,所以现在你有两个同时运行的线程,并且在一个线程上调用Thread.Sleep(int)不会影响另一个线程。请注意,您无需在 ProcessData 中调用Thread.Sleep(int),因为Timer会为您处理此问题。

最后,您希望在 ProcessData 再次运行时准确显示用户。您可以通过向计划类添加DateTime字段来执行此操作,例如private DateTime _lastRun;,并在 ProcessData 的开头,您可以将其设置为DateTime.Now。然后,在 startFeed 的循环中,您可以使用类似_lastRun.AddMinutes(5).Subtract(DateTime.Now).Seconds的内容计算下一次运行之前剩余的秒数。


这里可以说更多。正如其他人所暗示的那样,您正在编写轮询代码而不是事件驱动代码。轮询通常比事件驱动的等效项更慢,效率更低,更复杂。但是,这取决于您的数据源是否能够在有新数据要处理时通知您的代码;轮询可能是你唯一的选择。

关于线程之间的通信还有很多要说的。就其本身而言,多线程是一个非常棘手的主题,并且是许多难以发现的错误的原因。但是,对于此示例,写入控制台并设置共享DateTime字段应该在两个线程中是安全的。