Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
&引用;简单的;C#时间线程似乎冻结了_C#_Multithreading_Datetime - Fatal编程技术网

&引用;简单的;C#时间线程似乎冻结了

&引用;简单的;C#时间线程似乎冻结了,c#,multithreading,datetime,C#,Multithreading,Datetime,我盯着这条线已经有一段时间了,我相信我的思维已经停止了。我认为,为了更新UITextBox中的时间,最好的方法是创建一个简单的线程来获取时间并将其发回UI控件。在与它斗争了一段时间后,我感到沮丧,并认为我可以用其他方式增加时间。以冒险家无畏的精神,我将再次尝试 我在应用程序的其他地方有一个类似的线程,它获取一个列表并在TabControl中填充DataGridView。我本以为过程大致相同,但我遗漏了一个关键部分。整个螺纹如下所示: private void displayTime()

我盯着这条线已经有一段时间了,我相信我的思维已经停止了。我认为,为了更新UI
TextBox
中的时间,最好的方法是创建一个简单的线程来获取时间并将其发回UI控件。在与它斗争了一段时间后,我感到沮丧,并认为我可以用其他方式增加时间。以冒险家无畏的精神,我将再次尝试

我在应用程序的其他地方有一个类似的线程,它获取一个列表并在
TabControl
中填充
DataGridView
。我本以为过程大致相同,但我遗漏了一个关键部分。整个螺纹如下所示:

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;
    }
上面的线程已在多个位置启动(尝试调试),但当前处于表单的
显示的
事件处理程序中。形式开始出现,但随后一切似乎都挂起了。当我在线程中放置一个断点时,我可以无限地进行操作,但UI似乎永远无法恢复控制。我错过了什么?我很乐意详述任何被忽视的细节


编辑:说明:此线程正在处理所示事件的函数中启动。所示事件的描述如下:在首次显示表单时发生。我认为这可能会消除UI线程调用过快的理论。

问题在于,此处的while循环生成的事件太多,以至于事件队列被淹没:

while (true)
{
    // ...
    updateClock(time, date);
}
不必在线程中执行此操作,您可以使用以固定间隔生成事件,并为每个事件执行方法的一个步骤。这也意味着您不必在计时器在主线程上生成事件时使用Invoke

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

  • 有时,
    TimeOfDay.ToString()
    可能会输出一个恰好在第二次更改时命中的时间,在这种情况下,ToString()的结果将不是“12:23:34.00000”,而是“12:23:34”,这将导致您的方法引发异常
  • 您正在调用
    DateTime。现在
    两次,但该值可能在两次调用之间发生了更改。正常情况下,这并不重要,但当午夜过后,它可能会显示“23:59:99.999”,但这一天会显示为第二天。在这个应用程序中,这可能不是一个重大错误,但您应该养成只调用DateTime的习惯。现在,当您希望日期和时间的值一致时,只调用一次
要修复这些错误并简化代码,请执行以下操作:

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


您可能希望根据自己的需要进行调用。

这并不奇怪,因为您正在尽可能快地在UI线程消息队列中填充调用(使用BeginInvoke())。您可能希望在displayTime()线程中设置一个中断(即使用System.Threading.Thread.Sleep()),以便让UI线程有时间做一些工作。

如何调用
displayTime

如果您的Form.Show()方法如下所示

Show()
{
  displayTime();
}
然后,当您无限地阻塞主UI线程时

我会开始一个新的线程

Show()
{
   Action displayTimeAction = displayTime;

   displayTimeAction.BegingInvoke(null, null);
}

是 啊我现在意识到,Invoke和BeginInvoke之间的最大区别在于异步与同步的本质。这是一个很大的“哎呀”,也是一个教训。谢谢。你真的不想这么快就完成vanilla Invoke(),问题主要是你要求UI线程做事情的速度,而不是你要求它是同步还是异步完成的。这似乎也可以。我不知道最初是不是你发布了尝试Invoke()而不是BeginInvoke()(我相信是…),但最终解决了我的问题。是否有理由不使用Invoke()而改为使用计时器?@Rich Hoffman:您正在淹没事件队列。使用Invoke而不是BeginInvoke之所以有效,是因为它会导致线程在生成下一个事件之前等待表单更新,因此事件队列不会失控。但是,您仍然不必要地向事件队列发送大量事件,如果您同时尝试执行其他操作,可能会导致应用程序的响应出现问题。另一方面,计时器允许您控制事件的速率,而且您根本不需要额外的线程。这是一个简单得多的解决方案。我更新了我的帖子,以解决我认为是误解的问题。话虽如此,似乎我(拙劣的)尝试完成这项简单的任务可能带来了比预期更多的麻烦。计时器的解决方案很可能就是我的方式。这是UI和工作线程角色错误的一个很好的例子。人们对使用
BeginInvoke
Invoke
的热情如此高涨,以至于人们错过了颠倒角色的明显解决方案。也就是说,与其让工作线程将数据推送到UI线程,不如让UI线程轮询数据。这样做有很多好处。
Show()
{
   Action displayTimeAction = displayTime;

   displayTimeAction.BegingInvoke(null, null);
}