Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/274.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 - Fatal编程技术网

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。