引言

今天同事问了我一个问题,System.Windows.Forms.Timer是前台线程还是后台线程,我当时想的是它是跟着UI线程一起结束的,应该是前台线程吧?

我确实没有仔细研究过他们的异同,所以带着这个疑问探究一下System.Windows.Forms.Timer

System.Windows.Forms.Timer

机制

System.Windows.Forms.TimerWindows Forms 中的一个定时器控件,它的工作原理基于 Windows 消息循环机制。

这个Windows消息循环机制说简单一点就是它有一个消息队列,一个while(true) 循环结构,一个窗口消息处理函数,消息队列保存了在应用程序或系统中发生的各种事件和消息,如鼠标点击、键盘输入、窗口重绘等。循环结构消息队列中不断取出消息。然后通过窗口消息处理函数分发给相应的窗口过程进行处理。

System.Windows.Forms.Timer 的事件触发机制如下:

  • Timer 控件利用 Windows 的消息机制来触发 Tick 事件。在定时器启动后,它会在每个 Interval 时间间隔后,将一个 WM_TIMER 消息放入应用程序的消息队列。
  • WM_TIMER 是一个定时器消息,它是由 Windows 消息循环派发的。
  • 当应用程序处理消息循环时,当收到 WM_TIMER 消息,就会触发 Timer 的 Tick 事件。

源码解析

来通过源码看一下它的触发机制(这里节选了部分重要函数),它的源码还是比较简单的,仅有300多行。我们先来看一下 System.Windows.Forms.Timer 的调用,一般是这样使用:

using System.Windows.Forms;

// 创建一个 Timer 实例
Timer timer = new Timer();
// 设置触发间隔时间(以毫秒为单位)
timer.Interval = 1000; // 1000 毫秒 = 1 秒
// 绑定 Tick 事件处理程序
timer.Tick += Timer_Tick;
// 启动 Timer
timer.Start(); // Tick 事件处理程序
private void Timer_Tick(object sender, EventArgs e)
{
// 定时触发的操作
}

我们就按照上面的步骤来剖析一下源码:

第一步:创建实例

这一步并无特别,无参构造默认创建的实例默认 Interval 值为100。含参构造创建时会将该实例添加到参数容器中。

第二步:注册Tick

System.Windows.Forms.Timer 声明了一个 onTimer 委托,注册 Tick 是将注册的方法赋值给 onTimer 委托。

第三步:启动Timer

可以看到Timer的 Start()Stop(),实际都是给 Enabled 赋值,所以我们可以着重看一下 Enabled 属性的 Setter 方法。

第四步:TimerNativeWindow 启动

可以看到System.Windows.Forms.Timer 持有一个 TimerNativeWindow 类型的私有变量,是由这个私有变量启动的Timer.

第五步:TimerNativeWindow 实现

上一步中,可以看到当 Enable 置为 true 时,一个 TimerNativeWindow 类型的私有变量调用了 StartTimer(interval) 方法,那么来看一下这个 TimerNativeWindow 的实现。

如下图,可以看到当 TimerNativeWindow 调用 StartTimer()时,调用了 SafeNativeMethods.SetTimer 方法,传入了当前Timer的窗口句柄,还有加1后的 _timerID ,以及间隔 Interval

该方法的作用就是向Windows消息循环机制的消息队列中插入一条Timer消息。

上图中,我除了框出了StartTimer()方法,还框出了 WndProc(ref Message m) 方法。这个方法就很重要了。这个就是上面所说的 Windows 消息循环机制中的窗口消息处理函数

WndProc(ref Message m) 方法就是一个用于处理窗口消息的回调函数。当窗口接收到不同类型的消息时(例如鼠标事件、键盘事件、绘图事件等,包括Timer的触发事件),窗口过程会被调用来处理这些消息并作出相应的响应。

大家可能会很好奇该方法中的两个判断条件是什么意思?275 和 16 分别代表什么?

实际上这个是Windows消息标识符的十进制值。实际上他们是在名为 WinUser.h 的c++ 头文件中定义的。它随SDK一起安装到电脑上,可以通过Everything 直接找到它。

而我们要找的消息 275 和 16 就是下面这两个

  • WM_TIMER :其16进制为0x0113,转化为10进制则为275。
  • WM_CLOSE :其16进制为0x0010,转化为10进制则为16。

这样就可以理解WndProc(ref Message m) 方法的作用了,就是获取到 WM_TIMER 消息时,触发 System.Windows.Forms.TimerOnTick 方法。而获取到 WM_CLOSE 消息时,则调用 StopTimer(),结束定时器。

结论

通过上面的机制和源码分析,可以得出结论,System.Windows.Forms.Timer 并不是线程,而是依赖于UIx线程,依赖于Windows消息循环机制而实现的定时器。

所以回到开篇的问题,这个问题本身就有问题,System.Windows.Forms.Timer 并不是线程。

解读 --- System.Windows.Forms.Timer是前台线程吗?的更多相关文章

  1. System.Windows.Forms.Timer与System.Timers.Timer的区别(zz)

    .NET Framework里面提供了三种Timer: System.Windows.Forms.Timer System.Timers.Timer System.Threading.Timer VS ...

  2. System.Windows.Forms.Timer、System.Timers.Timer、System.Threading.Timer的 区别和用法

    System.Windows.Forms.Timer执行的时候,如果你在过程中间加一个sleep整个的界面就死掉了,但是另外两个没有这个情况,System.Timers.Timer.System.Th ...

  3. 简述System.Windows.Forms.Timer 与System.Timers.Timer用法区别

    System.Windows.Forms.Timer 基于窗体应用程序 阻塞同步 单线程 timer中处理时间较长则导致定时误差极大. System.Timers.Timer 基于服务 非阻塞异步 多 ...

  4. System.Windows.Forms.Timer、System.Timers.Timer、System.Threading.Timer的差别和分别什么时候用

    System.Windows.Forms.Timer.System.Timers.Timer.System.Threading.Timer的 区别和用法http://space.itpub.net/1 ...

  5. System.Windows.Forms.Timer

    一.主要属性.方法和事件 Windows 窗体 Timer 是定期引发事件的组件.该组件是为 Windows 窗体环境设计的. 时间间隔的长度由 Interval 属性定义,其值以毫秒为单位.若启用了 ...

  6. System.Windows.Forms.Timer反编译学习

    using System; using System.ComponentModel; using System.Globalization; using System.Runtime; using S ...

  7. System.Windows.Forms.Timer的简单用法

    Timer就是用来计时操作,如:你想在多少秒之后执行某个动作 Timer showTextBoxTimer = new Timer(); //新建一个Timer对象 showTextBoxTimer. ...

  8. System.Windows.Forms

    File: winforms\Managed\System\WinForms\DataGridView.cs Project: ndp\fx\src\System.Windows.Forms.cspr ...

  9. .net chart(图表)控件的使用-System.Windows.Forms.DataVisualization.dll

    这个案例指在介绍微软这套免费又功能强大的图表控件Microsoft Chart Controls for Microsoft .NET Framework 3.5,通过它,可让您的项目及报表,轻松套用 ...

  10. System.Windows.Forms.Control : Component, IOleControl, IOleObject, IOleInPlaceObject, IOleInPlaceActiveObject....

    #region 程序集 System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ...

随机推荐

  1. Netty服务端开发及性能优化

    作者:京东物流 王奕龙 Netty是一个异步基于事件驱动的高性能网络通信框架,可以看做是对NIO和BIO的封装,并提供了简单易用的API.Handler和工具类等,用以快速开发高性能.高可靠性的网络服 ...

  2. 【H5】Emmet 指令 HTML

    Emmet操作指南 HTML篇 生成带有内容的标签 标签名{内容}可以生成带有内容的标签 div{abc} <div>abc</div> 生成带有属性的标签 生成带有class ...

  3. 2022-03-22:二进制取反。 有一个二进制字符串,可以选择该串中的任意一段区间进行取反(可以进行一次或不进行),取反指将0变为1,将1变为0。那么取反之后的num可能的最大的字典序是多少呢。如有

    2022-03-22:二进制取反. 有一个二进制字符串,可以选择该串中的任意一段区间进行取反(可以进行一次或不进行),取反指将0变为1,将1变为0.那么取反之后的num可能的最大的字典序是多少呢.如有 ...

  4. 2022-03-08:给定一棵树的头节点head, 请按照题意,保留节点,没有保留的节点删掉。 树调整完之后,返回头节点。

    2022-03-08:给定一棵树的头节点head, 请按照题意,保留节点,没有保留的节点删掉. 树调整完之后,返回头节点. 答案2022-03-08: 递归.当前节点描黑或者子节点描黑,那就保留:否则 ...

  5. 测序数据学习笔记:bcl2fastq 安装

    相比二进制的 bcl2fastq2,基于 Perl 语言的 bcl2fastq-1.8.4 或许是从源码层面学习了解 Illumina 测序数据处理一个不错的选择.源码版本的 bcl2fastq-1. ...

  6. 24 式加速你的 Python

    一,分析代码运行时间 第1式,测算代码运行时间 平凡方法 快捷方法(jupyter环境) 第2式,测算代码多次运行平均时间 平凡方法 快捷方法(jupyter环境) 第3式,按调用函数分析代码运行时间 ...

  7. 云上使用 Stable Diffusion ,模型数据如何共享和存储

    随着人工智能技术的爆发,内容生成式人工智能(AIGC)成为了当下热门领域.除了 ChatGPT 之外,文本生成图像技术更令人惊艳. Stable Diffusion,是一款开源的深度学习模型.与 Mi ...

  8. 如何使用idea来查找所有未使用的代码?

    背景 项目组需要对开发的项目进行一次清理,把一些未被引用的代码清理掉. 我们知道一段代码未被引用,那么代码通常是灰色的. 但是一个完整的项目,会存在成千上万个Java文件,如果一个一个看去需要花费太多 ...

  9. 快速取模算法(Barrett Reduction)

    原理:取模运算低效的原因本质是除法运算的低效.如果能将除法变成其它运算就可以加速.具体地,将除以任意数转化成"乘一个数.除以一个 \(2^k\) "(取 \(2^{62}\) 即可 ...

  10. 【TVM教程】 自定义relay算子

    本文地址:https://www.cnblogs.com/wanger-sjtu/p/15046641.html 本文为tvm 教程的翻译版.这部分介绍了如何在tvm中添加新的relay算子,具体的是 ...