您的位置:首页 > 其它

关闭窗口后,这个过程仍然是重现和解决执行问题

2015-09-27 17:20 239 查看
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是无论线程有没有工作都强制关闭全部线程进而正常结束进程。

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

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

扩展阅读:

C# — WinForm 退出方法总结

阐述UI线程和Windows消息队列
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: