C# 线程安全事件-这是一个;“干净”;路?
我在一个专业库中偶然发现了一些代码,不确定这是否是处理跨线程事件调用的干净方法 下面的代码位于表单应用程序中。线程调用来自一个类,该类本身启动一个新线程并接收消息:C# 线程安全事件-这是一个;“干净”;路?,c#,multithreading,C#,Multithreading,我在一个专业库中偶然发现了一些代码,不确定这是否是处理跨线程事件调用的干净方法 下面的代码位于表单应用程序中。线程调用来自一个类,该类本身启动一个新线程并接收消息: private void Library_StatusChanged(object sender, AbstractTestCase.StatusChangedEventArgs e) { if (this.InvokeRequired) { this.lblProgress.Invoke((Meth
private void Library_StatusChanged(object sender, AbstractTestCase.StatusChangedEventArgs e)
{
if (this.InvokeRequired)
{
this.lblProgress.Invoke((MethodInvoker)delegate ()
{
lblProgress.Text = "Current state: " + e.Step;
lblProgress.Refresh();
}
);
this.pbProgess.Invoke((MethodInvoker)delegate ()
{
pbProgess.Value = e.Percentage;
pbProgess.Refresh();
});
this.lstStatus.Invoke((MethodInvoker)delegate ()
{
lstStatus.Items.Add(" " + e.Step);
lstStatus.Refresh();
});
this.Invoke((MethodInvoker)delegate ()
{
this.Refresh();
});
}
else
{
lblProgress.Text = "Current state:" + e.Step;
lblProgress.Refresh();
pbProgess.Value = e.Percentage;
pbProgess.Refresh();
lstStatus.Items.Add(" " + e.Step);
lstStatus.Refresh();
this.Refresh();
}
Application.DoEvents();
}
这是“最先进的”吗?我觉得有点乱 最新技术正在使用
wait
。如果这在这里不可能,至少将代码简化为一个Invoke
调用。不需要在每个控件上调用,只需在UI线程的任何位置调用即可
不需要进行invokererequired
检查,因为您应该知道事件是在哪个线程上引发的
在任何情况下,复制逻辑,例如“当前状态:”+e.Step
,都是一个糟糕的主意,无论发生什么,我都会在代码审查中失败
出现Application.DoEvents
是一个非常糟糕的迹象。可能是一种误解,因为只有在UI线程上调用它才有意义,但既然已经在UI线程上,为什么要调用它呢?!看起来很矛盾
lstStatus.Refresh()代码>也是一种误解,可能是迷信。控制自动刷新(如果允许事件处理)。使用invoke时,会在队列中添加一条语句,以供UI线程处理
使用以下简单的解决方案:
private void Library_StatusChanged(object sender, AbstractTestCase.StatusChangedEventArgs e)
{
this.lblProgress.Invoke((MethodInvoker)delegate ()
{
lblProgress.Text = "Current state: " + e.Step;
});
this.pbProgess.Invoke((MethodInvoker)delegate ()
{
pbProgess.Value = e.Percentage;
});
this.lstStatus.Invoke((MethodInvoker)delegate ()
{
lstStatus.Items.Add(" " + e.Step);
});
}
我通常使用Application.DoEvents
作为某种不正确的标志。如果只调用一个调用,而不是4个单独的调用,可能会更有效。库是单线程的(除了一些罕见的多线程部分),因此UI冻结。“因此UI冻结”而Application.DoEvents
是一种非常糟糕的掩盖问题的方法。这不是我的想法:)记住DoEvents的作用。它不会神奇地将堆栈放回线程的消息循环。它处理另一条消息。假设该消息导致库状态更改?我们现在递归地调用事件处理程序。如果这种情况持续发生,什么会阻止无限递归?这里没有我看到的代码。这段代码显然没有使用最佳实践,可能是由不了解消息处理的人编写的。这不是OPs代码。它来自图书馆。我假设他们不打算重写图书馆。他们只是问了一个关于他们遇到的代码的问题。Jup Matt,你说得对。我不喜欢lib,但免费是便宜的,便宜是好的,好是接近完美的,完美是,人们期望的:-/@AllDayPiano:我一定不同意。正如这段代码清楚地表明,“便宜”并不意味着“好”。哈哈,斯蒂芬,你是对的。但是不要告诉我-告诉我的上级:)嗨,usr,回答你的问题:调用是必需的,因为事件可能不是由同一个线程触发的。在另一个线程中运行异步com端口访问。这也可能发生,UI线程完全繁忙,因此DoEvent可能会重新绘制表单?!Control.Refresh()与lstStatus.Refresh()相同代码>也是一种误解,可能是迷信。Cargo cult programming.@MattBurland是的,这家伙做过一次,它隐藏了一个UI线程冻结,所以他现在永远认为这是解决方案。@AllDayPiano好的,所以我们总是需要调用。删除调用所需的检查<代码>也可能发生,UI线程完全繁忙
是一种糟糕的设计。严格说来,我不认为这是一个错误,但它是不受欢迎的。;后台线程上的DoEvents不执行任何操作,它必须在/a UI线程上运行。鉴于对DoEvents的调用,刷新调用是100%冗余的。所以这是一个结构性问题,对吗?但是,当CPU负载超过100%时,如何重新绘制表单?就我编程而言,我会启动另一个线程并异步运行UI。