zoukankan      html  css  js  c++  java
  • 关闭窗口后,这个过程仍然是重现和解决执行问题

    问题陈述

    在发展中,遇到这样的问题:

    点击程序主窗口右上角的叉号关闭应用程序后,程序的进程却没有关闭。

    通过查阅资料,了解到,产生此类问题的解决办法主要有下面两点:

    1)程序中存在死循环。

    2)程序为多线程程序。且在窗口关闭后。仍有线程在工作。

    本文将针对此类问题,进行重现并提出解决方式。

    场景再现

    @场景1

    新建Windows应用程序CloseWindowExp,程序每隔一秒钟改变一次窗口的背景色。

    程序执行后的效果,例如以下图所看到的(变化的过程,就请大家在脑子中想象一下吧)。

     

    程序的主要代码例如以下所看到的。

    //************************************************************
    //
    // 窗口关闭问题演示样例代码
    //
    // Author:三五月儿
    // 
    // Date:2014/07/27
    //
    // http://blog.csdn.net/yl2isoft
    //
    //************************************************************
     
    using System;
    using System.Drawing;
    using System.Threading;
    using System.Windows.Forms;
     
    namespace CloseWindowExp
    {
        public partial class frmCase1 : Form
        {
            Random rand = new Random();
            public frmCase1()
            {
                InitializeComponent();
            }
     
            private void button1_Click(object sender, EventArgs e)
            {
                while (true)
                {
                    int c1 = rand.Next(0, 244);
                    int c2 = rand.Next(0, 244);
                    int c3 = rand.Next(0, 244);
                    this.BackColor = Color.FromArgb(c1,c2,c3);
                    Application.DoEvents();
                    Thread.Sleep(1000);
                }
            }
        }
    }
    代码中,通过While循环来实现每隔一秒钟改变一次窗口背景色的工作,每一次循环中,会随机生成三个整数c1c2c3,并使用这三个整数来生成窗口的背景色,紧接着,运行Application.DoEvents()方法,使用此方法能够确保即使在循环中窗口也有反映(要不。你去掉再看看会有什么效果),每次循环的最后会让程序Sleep一小会(1s钟),这样就能够使颜色变化的间隔近似保持在1s钟左右。

    执行程序再点击窗口右上角的叉号关闭窗口(是关闭窗口哦,事实上曾经我一直都觉得。关闭了窗口也就关闭了程序,如今看来,这是不对的)。再打开任务管理器,打开“进程”项,在列表中寻找CloseWindowExp的身影,非常不幸。找到了,请看下图。

     

    @场景二

    场景二所给演示样例。完毕场景一演示样例一样的工作。仅仅是将工作转移至一个新的工作线程中。

    以下是场景二演示样例的主要代码。

    //************************************************************
    //
    // 窗口关闭问题演示样例代码
    //
    // Author:三五月儿
    // 
    // Date:2014/07/27
    //
    // http://blog.csdn.net/yl2isoft
    //
    //************************************************************
    using System;
    using System.Drawing;
    using System.Threading;
    using System.Windows.Forms;
     
    namespace CloseWindowExp1
    {
        public partial class frmCase2 : Form
        {
            Random rand = new Random();
            public frmCase2()
            {
                InitializeComponent();
            }
     
            private void button1_Click(object sender, EventArgs e)
            {
                Thread t = new Thread(()=>
                {
                    if (this.InvokeRequired)
                    {
                        this.Invoke(new Action(() => 
                        {
                            while (true)
                            {
                                int c1 = rand.Next(0, 244);
                                int c2 = rand.Next(0, 244);
                                int c3 = rand.Next(0, 244);
                                this.BackColor = Color.FromArgb(c1, c2, c3);
                                Application.DoEvents();
                                Thread.Sleep(1000);
                            }
                        }));
                    }
                });
                t.Start();
            }
        }
    }

    事实上。对于这里场景二所给的的演示样例,我是有一点不放心的,生怕使用它不能非常好地说明我想要表达的内容,由于本质上他跟演示样例一没有不论什么区别。都是由于在程序中存在一个死循环才导致了问题的发生。

    在研究这类问题发生的原因时,我们全然能够这样去考虑。当窗口被关闭后,程序为什么还在执行呢,肯定是由于程序还有没干完的工作,当然这件工作有可能再过一会就干完了。也有可能永远也干不完(死循环),至于这工作是谁干的。是主线程,还是工作线程,本质上没有差别。

    通过我们所给的两个实例,正好说明这点,由于实例一的工作是在主线程中完毕的。而实例二的工作是在工作线程中完毕的。可是,无论是主线程。还是工作线程。仅仅要存在未完毕的工作都会导致此类问题的发生。

    所以,此类问题的解决办法,终于能够归结为一点:关闭窗口时。仅仅要有线程还在工作。进程都不会被结束。

    在实际开发中。我们常常会使用一个工作线程去干一些反复的工作,所以。在多线程开发中。更easy出现死循环或者关闭了窗口还须要工作一段时间的场景。

    因此,多线程开发中更要注意此类问题的发生。

    找到了原因,解决这个问题就简单了。对于此类问题的解决。仅仅要确保在窗口关闭后没有不论什么线程在工作就可以

    至于详细解决方式能够视情况而定。

    3 解决方法

    @方法1

    将循环条件while (true)改动为while (this.Visible)。

    这样一来,当窗口关闭后,窗口的Visible属性值变为false。则while循环随即被终止。进而进程也会被正常结束。

    @方法2

    在窗口的FormClosing事件处理方法中,使用代码System.Environment.Exit(0)强制退出当前进程。这样一来,无论进程下是否还有线程在工作,都会一概结束。

    private void frmCase2_FormClosing(object sender, FormClosingEventArgs e)
    {
         System.Environment.Exit(0);
    }
    方法1的原理是结束程序中的死循环进而结束线程,从而使进程可以正常结束。而方法2是无论线程有没有工作都强制关闭全部线程进而正常结束进程。

    我们这里不去探讨哪种方法更好。仅仅想对解决此类问题的思考方向给出一个说明。那就是:通过结束全部线程的工作来保证进程的正常结束。当然这也是本文的一个主题。

    好了,就写到这里了。希望没有离题。

     扩展阅读:

    C# — WinForm 退出方法总结

    阐述UI线程和Windows消息队列

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    Go Example--方法
    Go Example--结构体
    Flutter项目实操---我的界面搭建、开源中国API流程了解、HTTP请求封装、登录处理<二>
    Java精通并发-CAS底层实现与AtomicInteger源码剖析、关于CAS问题描述
    大数据JavaWeb之JDBC基础----快速入门、各个类详解(DriverManager、Connection、Statement)
    Flutter项目实操---开源中国之项目说明、基础框架搭建、基础BottomBar、侧滑菜单<一>
    Kotlin项目实战之手机影音---主界面tab切换、home界面适配、获得首页网络数据
    android高级UI之Canvas综合案例操练
    开启Fluter基础之旅<六>-------自定义View、牛逼动画效果
    Z-score
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4842447.html
Copyright © 2011-2022 走看看