关闭窗体后,进程仍然在运行的问题重现与解决
1?問題陳述
在開發(fā)中,遇到這樣一個(gè)問題:
點(diǎn)擊程序主窗體右上角的叉號(hào)關(guān)閉應(yīng)用程序后,程序的進(jìn)程卻沒有關(guān)閉。
通過查閱資料,了解到,產(chǎn)生此類問題的原因主要有以下兩點(diǎn):
1)程序中存在死循環(huán)。
2)程序?yàn)槎嗑€程程序,且在窗體關(guān)閉后,仍有線程在工作。
本文將針對(duì)此類問題,進(jìn)行重現(xiàn)并提出解決方案。
2?場景再現(xiàn)
@場景1
新建Windows應(yīng)用程序CloseWindowExp,程序每隔一秒鐘改變一次窗體的背景色。
程序運(yùn)行后的效果,如下圖所示(變化的過程,就請(qǐng)大家在腦子中想象一下吧)。
程序的主要代碼如下所示。
//************************************************************
//
// 窗體關(guān)閉問題示例代碼
//
// 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循環(huán)來實(shí)現(xiàn)每隔一秒鐘改變一次窗體背景色的工作,每一次循環(huán)中,會(huì)隨機(jī)生成三個(gè)整數(shù)c1、c2、c3,并使用這三個(gè)整數(shù)來生成窗體的背景色,緊接著,執(zhí)行Application.DoEvents()方法,使用此方法可以確保即使在循環(huán)中窗體也有反映(要不,你去掉再看看會(huì)有什么效果),每次循環(huán)的最后會(huì)讓程序Sleep一小會(huì)(1s鐘),這樣就可以使顏色變化的間隔近似保持在1s鐘左右。
運(yùn)行程序再點(diǎn)擊窗體右上角的叉號(hào)關(guān)閉窗體(是關(guān)閉窗體哦,其實(shí)以前我一直都認(rèn)為,關(guān)閉了窗體也就關(guān)閉了程序,現(xiàn)在看來,這是不正確的),再打開任務(wù)管理器,打開“進(jìn)程”項(xiàng),在列表中尋找CloseWindowExp的身影,很不幸,找到了,請(qǐng)看下圖。
@場景二
場景二所給示例,完成場景一示例一樣的工作,只是將工作轉(zhuǎn)移至一個(gè)新的工作線程中。
下面是場景二示例的主要代碼。
//************************************************************
//
// 窗體關(guān)閉問題示例代碼
//
// 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();
}
}
}
其實(shí),對(duì)于這里場景二所給的的示例,我是有一點(diǎn)不放心的,生怕使用它不能很好地說明我想要表達(dá)的內(nèi)容,因?yàn)楸举|(zhì)上他跟示例一沒有任何差別,都是因?yàn)樵诔绦蛑写嬖谝粋€(gè)死循環(huán)才導(dǎo)致了問題的發(fā)生。
在研究這類問題發(fā)生的原因時(shí),我們完全可以這樣去考慮,當(dāng)窗體被關(guān)閉后,程序?yàn)槭裁催€在運(yùn)行呢,肯定是因?yàn)槌绦蜻€有沒干完的工作,當(dāng)然這件工作有可能再過一會(huì)就干完了,也有可能永遠(yuǎn)也干不完(死循環(huán)),至于這工作是誰干的,是主線程,還是工作線程,本質(zhì)上沒有區(qū)別。通過我們所給的兩個(gè)實(shí)例,正好說明這點(diǎn),因?yàn)閷?shí)例一的工作是在主線程中完成的,而實(shí)例二的工作是在工作線程中完成的。但是,不管是主線程,還是工作線程,只要存在未完成的工作都會(huì)導(dǎo)致此類問題的發(fā)生。所以,此類問題的原因,最終可以歸結(jié)為一點(diǎn):關(guān)閉窗體時(shí),只要有線程還在工作,進(jìn)程都不會(huì)被結(jié)束。
在實(shí)際開發(fā)中,我們經(jīng)常會(huì)使用一個(gè)工作線程去干一些重復(fù)的工作,所以,在多線程開發(fā)中,更容易出現(xiàn)死循環(huán)或者關(guān)閉了窗體還需要工作一段時(shí)間的場景。因此,多線程開發(fā)中更要注意此類問題的發(fā)生。
找到了原因,解決問題就簡單了。對(duì)于此類問題的解決,只要確保在窗體關(guān)閉后沒有任何線程在工作即可。至于具體解決方案可以視情況而定。
3 解決方法
@方法1
將循環(huán)條件while?(true)修改為while?(this.Visible)。
這樣一來,當(dāng)窗體關(guān)閉后,窗體的Visible屬性值變?yōu)閒alse,則while循環(huán)隨即被終止,進(jìn)而進(jìn)程也會(huì)被正常結(jié)束。
@方法2
在窗體的FormClosing事件處理方法中,使用代碼System.Environment.Exit(0)強(qiáng)制退出當(dāng)前進(jìn)程,這樣一來,不管進(jìn)程下是否還有線程在工作,都會(huì)一概結(jié)束。
private void frmCase2_FormClosing(object sender, FormClosingEventArgs e)
{
System.Environment.Exit(0);
}
方法1的原理是結(jié)束程序中的死循環(huán)進(jìn)而結(jié)束線程,從而使進(jìn)程能夠正常結(jié)束;而方法2是不管線程有沒有工作都強(qiáng)制關(guān)閉所有線程進(jìn)而正常結(jié)束進(jìn)程。
我們這里不去探討哪種方法更好,只想對(duì)解決此類問題的思考方向給出一個(gè)說明,那就是:通過結(jié)束所有線程的工作來保證進(jìn)程的正常結(jié)束。當(dāng)然這也是本文的一個(gè)主題。
好了,就寫到這里了,希望沒有離題。
---------------------
總結(jié)
以上是生活随笔為你收集整理的关闭窗体后,进程仍然在运行的问题重现与解决的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4.9利率上浮25%是多少
- 下一篇: dataGridView使用指南系列一、