前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >解读 --- System.Windows.Forms.Timer是前台线程吗?

解读 --- System.Windows.Forms.Timer是前台线程吗?

作者头像
Niuery Diary
发布2023-10-22 17:05:08
1790
发布2023-10-22 17:05:08
举报
文章被收录于专栏:Niuery的技术日记

引言

今天同事问了我一个问题,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 的调用,一般是这样使用:

代码语言:javascript
复制
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 并不是线程。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Niuery Diary 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • System.Windows.Forms.Timer
    • 机制
      • 源码解析
      • 结论
      相关产品与服务
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档