• WinForm“假死”问题汇总


    一、一处消息死锁分析

    最近维护一个工控机上运行的winform程序,我的前任在一个弹出窗口(窗口B)里面调用了ShowDialog方法弹出对话框(窗口C),导致了一个问题是有时关闭窗口C时程序假死(无规律),最后用windbg远程调试找到了问题。

    解决方法如下:用一个委托来执行ShowDialog。

    public delegate DialogResult DelegateShowMessageForm(string msg);

    参考资料:一处消息死锁分析

     

    最近做winform程序时,在主窗口用线程加了个刷新电量的线程(用于实现充电状态的效果),后面导致其他窗口关闭时假死。

    用DebugView抓取Debug信息后发现,该窗口的From_Closing事件和Close方法都执行完了,但窗口未关闭。最后将刷新电量的线程取消,改用下文方法,贴上部分代码。

            int i = 0; //用于充电时刷新电池图片
            private void ChangeBatteryPic(IDModulePower power)
            {
    
    
                if (!currIDModulePower.Equals(power))
                {
                    int picNum = power.QuantityOfBattery;
                    switch (power.PowerStatus)
                    {
                        case IDModulePowerStatus.ExternalPower:
                            picNum = 7;
                            RefreshBatteryPic(picNum);
                            break;
                        case IDModulePowerStatus.BatteryPower:
                            RefreshBatteryPic(picNum);
                            break;
                        case IDModulePowerStatus.OnCharging:
                            {
                                if (i < 6)
                                {
                                    i++;
                                }
                                else
                                {
                                    i = 0;
                                }
                                RefreshBatteryPic(i);
                            }
                            break;
                        case IDModulePowerStatus.ChargeException:
                            picNum = 6;
                            RefreshBatteryPic(picNum);
                            break;
                        default:
                            break;
                    }
    
                    currIDModulePower = power;
                }
    
            }
    
            public delegate void RefreshControl(int i);
    
            private void RefreshBatteryPic(int picNum)
            {
                if (this.InvokeRequired)
                {
                    this.BeginInvoke(new RefreshControl(RefreshBatteryPic), picNum);
                }
                else
                {
                    this.pbBattery.BackgroundImage = VALWELL.SSLC.Resource.Resources.CurrBatteryStatus(picNum);
                    this.pbBattery.BackgroundImageLayout = ImageLayout.Center;
                    Application.DoEvents();
                }
            }

    Control的Invoke和BeginInvoke

    对于这两个方法,首先我们要有以下的认识:
      1. Control.Invoke,Control.BeginInvoke和delegate.Invoke,delegate.BeginInvoke是不同的。
      2. Control.Invoke中的委托方法,执行在主线程,也就是我们的UI线程。而Control.BeginInvoke从命名上来看虽然具有异步调用的特征(Begin),但也仍然执行在UI线程。
      3. 如果在UI线程中直接调用Invoke和BeginInvoke,数据量偏大时,依然会造成UI的假死。
      有很多开发者在初次接触这两个函数时,很容易就将它们同异步联系起来、有些人会认为他们是独立于UI线程之外的工作线程,实际上,他们都被这两个函数的命名所蒙蔽了。如果以传统调用异步的方式,直接调用Control.BeginInvoke,与同步函数的执行无异,UI线程还是会处理所有辛苦的操作,造成我们的应用程序阻塞。
      Control.Invoke的调用模型很明确:在UI线程中以代码顺序同步执行,因此,抛开工作线程调用UI元素的干扰,我们可以将Control.Invoke视为同步,本文不做过多介绍。
      很多开发者在接触异步后,再来处理窗体假死的问题,很容易想当然的将Control.BeginInvoke视为WinForm封装的异步。

     

  • 相关阅读:
    JSP所需要掌握的部分
    Parameter index out of range (1 > number of parameters, which is 0).
    Servlet到Servlet的请求转发与重定向的区别
    servlet范围:数据共享
    hihocoder 1169 猜数字
    UVA 1149 Bin Packing
    Using a Comparison Function for the Key Type
    STL Iterators
    SPOJ Pouring Water
    求DAG上两点的最短距离
  • 原文地址:https://www.cnblogs.com/cheng2015/p/5150834.html
Copyright © 2020-2023  润新知