关闭窗体后,进程仍然在运行的问题重现与解决
2014-07-27 11:43
423 查看
1 问题陈述
在开发中,遇到这样一个问题:
点击程序主窗体右上角的叉号关闭应用程序后,程序的进程却没有关闭。
通过查阅资料,了解到,产生此类问题的原因主要有以下两点:
1)程序中存在死循环。
2)程序为多线程程序,且在窗体关闭后,仍有线程在工作。
本文将针对此类问题,进行重现并提出解决方案。
2 场景再现
@场景1
新建Windows应用程序CloseWindowExp,程序每隔一秒钟改变一次窗体的背景色。
程序运行后的效果,如下图所示(变化的过程,就请大家在脑子中想象一下吧)。
![](https://img-blog.csdn.net/20140727112454097?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWwyaXNvZnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
程序的主要代码如下所示。
运行程序再点击窗体右上角的叉号关闭窗体(是关闭窗体哦,其实以前我一直都认为,关闭了窗体也就关闭了程序,现在看来,这是不正确的),再打开任务管理器,打开“进程”项,在列表中寻找CloseWindowExp的身影,很不幸,找到了,请看下图。
![](https://img-blog.csdn.net/20140727112714185?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWwyaXNvZnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
@场景二
场景二所给示例,完成场景一示例一样的工作,只是将工作转移至一个新的工作线程中。
下面是场景二示例的主要代码。
其实,对于这里场景二所给的的示例,我是有一点不放心的,生怕使用它不能很好地说明我想要表达的内容,因为本质上他跟示例一没有任何差别,都是因为在程序中存在一个死循环才导致了问题的发生。
在研究这类问题发生的原因时,我们完全可以这样去考虑,当窗体被关闭后,程序为什么还在运行呢,肯定是因为程序还有没干完的工作,当然这件工作有可能再过一会就干完了,也有可能永远也干不完(死循环),至于这工作是谁干的,是主线程,还是工作线程,本质上没有区别。通过我们所给的两个实例,正好说明这点,因为实例一的工作是在主线程中完成的,而实例二的工作是在工作线程中完成的。但是,不管是主线程,还是工作线程,只要存在未完成的工作都会导致此类问题的发生。所以,此类问题的原因,最终可以归结为一点:关闭窗体时,只要有线程还在工作,进程都不会被结束。
在实际开发中,我们经常会使用一个工作线程去干一些重复的工作,所以,在多线程开发中,更容易出现死循环或者关闭了窗体还需要工作一段时间的场景。因此,多线程开发中更要注意此类问题的发生。
找到了原因,解决问题就简单了。对于此类问题的解决,只要确保在窗体关闭后没有任何线程在工作即可。至于具体解决方案可以视情况而定。
3 解决方法
@方法1
将循环条件while (true)修改为while (this.Visible)。
这样一来,当窗体关闭后,窗体的Visible属性值变为false,则while循环随即被终止,进而进程也会被正常结束。
@方法2
在窗体的FormClosing事件处理方法中,使用代码System.Environment.Exit(0)强制退出当前进程,这样一来,不管进程下是否还有线程在工作,都会一概结束。
我们这里不去探讨哪种方法更好,只想对解决此类问题的思考方向给出一个说明,那就是:通过结束所有线程的工作来保证进程的正常结束。当然这也是本文的一个主题。
好了,就写到这里了,希望没有离题。
扩展阅读:
C# — WinForm 退出方法总结
细说UI线程和Windows消息队列
在开发中,遇到这样一个问题:
点击程序主窗体右上角的叉号关闭应用程序后,程序的进程却没有关闭。
通过查阅资料,了解到,产生此类问题的原因主要有以下两点:
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(); } } }
其实,对于这里场景二所给的的示例,我是有一点不放心的,生怕使用它不能很好地说明我想要表达的内容,因为本质上他跟示例一没有任何差别,都是因为在程序中存在一个死循环才导致了问题的发生。
在研究这类问题发生的原因时,我们完全可以这样去考虑,当窗体被关闭后,程序为什么还在运行呢,肯定是因为程序还有没干完的工作,当然这件工作有可能再过一会就干完了,也有可能永远也干不完(死循环),至于这工作是谁干的,是主线程,还是工作线程,本质上没有区别。通过我们所给的两个实例,正好说明这点,因为实例一的工作是在主线程中完成的,而实例二的工作是在工作线程中完成的。但是,不管是主线程,还是工作线程,只要存在未完成的工作都会导致此类问题的发生。所以,此类问题的原因,最终可以归结为一点:关闭窗体时,只要有线程还在工作,进程都不会被结束。
在实际开发中,我们经常会使用一个工作线程去干一些重复的工作,所以,在多线程开发中,更容易出现死循环或者关闭了窗体还需要工作一段时间的场景。因此,多线程开发中更要注意此类问题的发生。
找到了原因,解决问题就简单了。对于此类问题的解决,只要确保在窗体关闭后没有任何线程在工作即可。至于具体解决方案可以视情况而定。
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消息队列
相关文章推荐
- C# 关闭登录窗体,进入主窗体后,主窗体关闭,程序进程仍在运行的问题
- C# 关闭登录窗体,进入主窗体后,主窗体关闭,程序进程仍在运行的问题
- C#关闭登录窗体,进入主窗体后,主窗体关闭,程序进程仍在运行的问题
- C# 关闭登录窗体,进入主窗体后,主窗体关闭,程序进程仍在运行的问题
- 关于C#关闭窗体后,依旧有后台进程在运行的解决方法
- 关闭窗口后,这个过程仍然是重现和解决执行问题
- VS2012 WIN7下使用DotNetBar 使用Office2007Form皮肤 窗体运行不显示问题解决方法
- C# 启动线程后,关闭form窗体,进程未关闭问题
- 解决winform关闭打开的窗体问题
- MDI窗体关闭问题解决一例
- 帮你解决DevExpress ASPxPopupControl窗体的显示与关闭问题(转载)
- 关闭winform窗体时,出现了bug,貌似微软VS.NET2005的问题,请教大家该如何解决
- 解决调试asp.net程序时无法修改代码的问题(提示: 当调试器已经附加到已经运行的进程...)
- C#窗体程序,当窗口关闭后,进程无法关闭解决方法
- Form窗体点击关闭按钮并未关闭进程的解决方法
- java2Word中关闭不了WINWORD进程问题的解决
- Form窗体点击关闭按钮并未关闭进程的解决方法
- MFC关于解决点击关闭,对话框仍有后台程序运行问题 .
- MFC窗体程序作为服务运行注销登录后不能关机的问题解决
- 主窗体关闭后登录窗体仍然运行