“简单”C#时间线程似乎正在冻结

时间:2010-10-20 18:59:11

标签: c# multithreading datetime

我一直盯着这个帖子已经有一段时间了,我相信我的思绪已经关闭了。认为最好的事情是,为了更新UI TextBox中的时间,将创建我认为是一个简单的线程来获取时间并将其发布回UI控件。在与它争吵了一段时间后,我感到沮丧并且认为我可能只是以其他方式增加时间。在冒险家的强悍精神中,我再给它一次。

我在应用程序的其他位置运行了一个类似的线程,该线程采用列表并填充DataGridView中的TabControl。我原以为这个过程大致相同,但我错过了一个关键部分。整个主题如下:

private void displayTime()
    {
        while (true)
        {
            String time;
            String date;

            time = DateTime.Now.TimeOfDay.ToString();
            int len = time.IndexOf('.');
            time = time.Substring(0, len);
            date = DateTime.Now.Date.ToString();
            len = date.IndexOf(' ');
            date = date.Substring(0, len);

            updateClock(time, date);
        }
    }
private void updateClock(String time, String date)
    {
        if (InvokeRequired)
        {
            BeginInvoke(new timeDel(updateClock), new object[] {time, date});
            return;
        }           

        ctrlTimeTxt.Text = time + "\n" + date;
    }

上面的线程已在各个地方启动(试图调试),但目前在Form的Shown事件处理程序中。表格开始出现,但一切似乎都挂了。当我在线程中放置一个断点时,我可以步骤 ad infinitum ,但UI似乎永远无法控制回来。我错过了什么?我很乐意扩展任何被忽视的细节。

编辑:澄清:此线程正在处理已显示事件的函数中启动。 Shown 事件的描述如下:每当首次显示Form时发生。我认为这可能会消除UI线程调用太快的理论。

3 个答案:

答案 0 :(得分:5)

问题是你的while循环产生了很多事件,事件队列被淹没了:

while (true)
{
    // ...
    updateClock(time, date);
}

您可以使用Timer定期生成事件,而不是在线程中执行此操作,并为每个事件执行一个方法步骤。这也意味着您不必使用Invoke,因为计时器会在主线程上生成事件。

您的代码中还有两个其他错误:

  • 偶尔TimeOfDay.ToString()可能会输出一个完全达到第二次更改的时间,在这种情况下,ToString()的结果不会是“12:23:34.00000”而只是“12:23:34”会导致你的方法抛出异常。
  • 您正在调用DateTime.Now两次,但两次调用之间的值可能已更改。通常这没关系,但是当它通过午夜时它可以显示'23:59:99.999',但是这一天显示为第二天。这可能不是这个应用程序中的一个重大错误,但你应该习惯只调用DateTime.Now一次你需要一致的日期和时间值。

修复这些错误并简化代码:

  • 在表单中添加计时器。
  • 在设计器中将计时器的Enabled属性设置为true
  • 将此事件处理程序添加到Tick事件:

    private void timer_Tick(object sender, EventArgs e)
    {
        DateTime now = DateTime.Now;
        textBox1.Text = now.ToString("HH:mm:ss\nyyyy-MM-dd");
    }
    

根据您的需要,您可能希望adjust the format string

答案 1 :(得分:4)

这并不让我感到惊讶,因为这样做不顺利 - 你在UI线程消息队列(使用BeginInvoke())中填充调用的速度与生成它们的速度一样快。您可能希望在displayTime()线程中放置一个中断(即使用System.Threading.Thread.Sleep()),以便为UI线程提供时间来完成某些工作。

答案 2 :(得分:2)

你如何致电displayTime

如果你的Form.Show()方法是这样的

Show()
{
  displayTime();
}

然后作为Mark answered,您将无限地阻止主UI线程。

我会开始一个新线程

Show()
{
   Action displayTimeAction = displayTime;

   displayTimeAction.BegingInvoke(null, null);
}