1 问题陈述
在发展中,遇到这样的问题:
点击程序主窗口右上角的叉号关闭应用程序后,程序的进程却没有关闭。
通过查阅资料,了解到,产生此类问题的解决办法主要有下面两点:
1)程序中存在死循环。
2)程序为多线程程序。且在窗口关闭后。仍有线程在工作。
本文将针对此类问题,进行重现并提出解决方式。
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循环来实现每隔一秒钟改变一次窗口背景色的工作,每一次循环中,会随机生成三个整数c1、c2、c3,并使用这三个整数来生成窗口的背景色,紧接着,运行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是无论线程有没有工作都强制关闭全部线程进而正常结束进程。
我们这里不去探讨哪种方法更好。仅仅想对解决此类问题的思考方向给出一个说明。那就是:通过结束全部线程的工作来保证进程的正常结束。当然这也是本文的一个主题。
好了,就写到这里了。希望没有离题。
扩展阅读:
版权声明:本文博主原创文章,博客,未经同意不得转载。