如何在C#

时间:2017-04-10 17:39:19

标签: c# multithreading invoke begininvoke invokerequired

我有一个C#程序似乎在随机时间卡住了,并且随机一段时间它恢复了自己!当它卡住时,我可以看到内存增长,当它恢复时,内存使用率就会降到正常水平。 CPU使用率一直都很正常,没有文件写入或读取(按设计)。

程序调用外部(第三方)DLL函数与硬件通信,并从DLL的回调中更新UI,该回调在不同的线程上运行。我检查了代码,发现除了以下代码(编辑)之外没有任何可疑之处:

private void Func(StructType para) {
    if (labelA.InvokeRequired) {
        labelA.BeginInvoke(new MethodInvoker(() => Func(para)));
        return;
    }
    if (labelB.InvokeRequired) {
        labelB.BeginInvoke(new MethodInvoker(() => Func(para)));
        return;
    }
    labelA.Text = para.A;
    labelB.Text = para.B;
}

我想知道这是否是从另一个线程更新UI元素的正确方法?如果没有,如何修改它?

实际上,我调用了6个标签和另一个表单(可选)。它似乎在大多数时间都很好,但偶尔会卡住。由于显而易见的原因,我无法在此发布所有代码,但只是试图从我最怀疑的地方进行麻烦。

提前感谢任何建议!

1 个答案:

答案 0 :(得分:-1)

您不需要单独检查每个控件以确定是否需要调用它 - 只有一个UI线程,因此,该检查仅有一次。请记住 - 修改任何UI组件几乎肯定会级联到其他UI组件的大量其他读取/写入;因此,您必须假设如果您正在触摸任何 UI对象,则必须假设您正在触摸所有 UI组件。

考虑到这一点,我建议您执行一次调用检查,我建议在两个标签的父控件上执行检查和调用。

假设this引用作为这两个标签的父级的类,我会修改您的代码,如下所示:

private void Func(StructType para) {
    if (this.InvokeRequired) {

        // Elide the explicit delegate declaration; it's not necessary.
        this.BeginInvoke( Func(para) );

        // Elide the return statement - multiple returns are messy, and in this case, easily removed.
    }
    else {
       labelA.Text = para.A;
       labelB.Text = para.B;
   }
}

请注意,如果对象被释放,InvokeRequired将返回false,即使调用线程不是UI线程。