zoukankan      html  css  js  c++  java
  • 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封装的异步。

     

  • 相关阅读:
    leetcode Remove Linked List Elements
    leetcode Word Pattern
    leetcode Isomorphic Strings
    leetcode Valid Parentheses
    leetcode Remove Nth Node From End of List
    leetcode Contains Duplicate II
    leetcode Rectangle Area
    leetcode Length of Last Word
    leetcode Valid Sudoku
    leetcode Reverse Bits
  • 原文地址:https://www.cnblogs.com/cheng2015/p/5150834.html
Copyright © 2011-2022 走看看