关闭窗体后,进程仍然在运行的问题重现与解决

2023-05-16

问题陈述

在开发中,遇到这样一个问题:

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

通过查阅资料,了解到,产生此类问题的原因主要有以下两点:

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循环来实现每隔一秒钟改变一次窗体背景色的工作,每一次循环中,会随机生成三个整数 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消息队列

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关闭窗体后,进程仍然在运行的问题重现与解决 的相关文章

随机推荐

  • parse error on line 1, column 4: bare “ in non-quoted-field

    golang报错 xff1a parse error on line 1 column 4 bare 34 in non quoted field 可能的原因是csv是windowns 导出的 xff0c 编码方式是UTF 8 BOM 方式
  • CPU和GPU性能指标收集

    这里的CPU是AMD的芯片 总的性能指标 Total mem Bw Total mem RdBw Total mem WrBw uperf PCIE 上行带宽 上行 网卡到内存 通过 uperf 查看 XGMI uperf NVLink 带
  • PX4 Bootloader解析

    1 引言 半年前入手了Pixhawk V2全套硬件 xff0c 编译好的开源固件也下了 xff0c 四轴也飞了 xff0c 一直想对这套开源飞控进行一个系统地解析 xff0c 由于工作原因一直没时间 最近翻开了PX4飞控源代码 xff0c
  • 进程内存使用

    查看进程内存使用 28028 是进程的pid top p 28028 还可以查看进程的status文件 xff1a cat proc 28028 status VmRSS对应的值就是物理内存占用 内存占用比较多的程序 ps aux sort
  • perf使用

    perf可记录高达700多种events事件 sudo perf list 可以查看可以perf的事件 sudo perf record F 999 e cpu clock faults a g p 28544 sleep 60 制定进程7
  • gperftools

    gperftools 实现了更高性能的多线程的malloc 实现 增加了极好的性能分析工具 gperftools 的前身是 pprof https github com google pprof sudo apt get install a
  • RDMA 设备查看

    1硬件检测 1 1检查硬件是否安装 确认硬件已安装 lspci tvm grep Mellanox 查看OFED驱动版本命令 如果没有驱动可以参考 https km sankuai com page 335338645 安装 rpm qa
  • spark 转换tfrecord 成parquet格式

    读取tfrecord 成parquet文件格式 read tfrecord py coding utf 8 34 34 34 读取tfrecord生成parquet文件格式 34 34 34 import os import time im
  • ffmpeg压缩视频

    安装ffmpeg conda install c conda forge x264 61 61 39 1 161 3030 39 ffmpeg 61 4 3 2 压缩mov视频 ffmpeg i movie mov c v libx264
  • AI行动,解放做表打工人

    1 atomecho 插件介绍 如果你是个 需要做财报 数据新闻的冤种 xff1b 或者是 网上有的我都想要 的囤积狂魔 xff1b 或是沉迷 Ctrl 43 C Ctrl 43 V 的做表工具人 那你一定不陌生 对不上的格式 找不到的数据
  • golang高性能rocksdb参数配置

    golang高性能rocksdb参数配置 import 34 errors 34 34 log 34 34 monorepo service autotable comm grocksdb 34 34 strings 34 34 githu
  • Linux doc和docx转换pdf

    准备工作 服务器安装libreoffice apt get install libreoffice 安装完成libreoffice后 xff0c 测试是否安装成功 soffice h 例子 把 tmp test docx 转换成 tmp t
  • 多个硬盘挂载到同一个目录

    同一目录无法重复挂载 xff0c 后挂载的会覆盖之前挂载的磁盘 但是现在需要将4块磁盘并行挂载 xff0c 该如何操作呢 xff1f 将2块磁盘合并到一个逻辑卷 进行挂载 基本知识 基本概念PV Physical Volume 物理卷物理卷
  • LeetCode 跳跃游戏 题解

    题述 xff1a 给定一个非负整数数组 nums xff0c 你最初位于数组的 第一个下标 数组中的每个元素代表你在该位置可以跳跃的最大长度 判断你是否能够到达最后一个下标 思路 xff1a 阅读题目我们可以发现只要数组里面没有0 我们就一
  • #error This file was generated by a newer version of protoc which is 【protoc版本问题】

    在github上下载自己适合的protoc版 xff08 我的环境是ubuntu18 04 ros melodic版本 xff09 gazebo9对应的最低版本protoc为3 0 0 我之前版本为3 14 0会提示目前文件由旧版本生成 x
  • Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析

    前段时间 xff0c 公司同事开发了一个小工具 xff0c 在工具执行过程中 xff0c UI 界面一直处于卡死状态 通过阅读代码发现 xff0c 主要是由于 Dispatcher BeginInvoke 方法使用不当导致的 本文将通过一个
  • List的Clear方法与RemoveAll方法用法小结

    示例代码 using System using System Collections Generic namespace ListClearExp class Program static void Main string args Lis
  • 利用C#访问注册表获取软件的安装路径

    绝大多数软件 xff0c 基本上都会在注册表中记录自己的名字和安装路径信息 在注册表中记录这些信息的位置是 xff1a HKEY LOCAL MACHINE SOFTWARE Microsoft Windows CurrentVersion
  • 使用ValidationRule类来检查用户输入的有效性

    1 新建WPF应用程序ValidationRuleExp 整个程序的结构如下图所示 程序运行起来后的效果如下图所示 用户操作程序时 xff0c 先输入固话 手机 Email 个人网站等信息 xff0c 再点击右侧的 点我记住你 按钮 xff
  • 关闭窗体后,进程仍然在运行的问题重现与解决

    1 问题陈述 在开发中 xff0c 遇到这样一个问题 xff1a 点击程序主窗体右上角的叉号关闭应用程序后 xff0c 程序的进程却没有关闭 通过查阅资料 xff0c 了解到 xff0c 产生此类问题的原因主要有以下两点 xff1a 1 x