欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析

程序员文章站 2023-12-16 09:45:46
本文实例讲述了c#中forms.timer、timers.timer、threading.timer的用法分析,分享给大家供大家参考。具体分析如下: 在.net fram...

本文实例讲述了c#中forms.timer、timers.timer、threading.timer的用法分析,分享给大家供大家参考。具体分析如下:

在.net framework里面提供了三种timer

① system.windows.forms.timer

② system.timers.timer

③ system.threading.timer

现分述如下:

一、system.windows.forms.timer

1、基于windows消息循环,用事件方式触发,在界面线程执行;是使用得比较多的timer,timer start之后定时(按设定的interval)调用挂接在tick事件上的evnethandler。在这种timer的eventhandler中可 以直接获取和修改ui元素而不会出现问题--因为这种timer实际上就是在ui线程自身上进行调用的。

2、它是一个基于form的计时器
3、创建之后,你可以使用interval设置tick之间的跨度,用委托(delegate)hook tick事件
4、调用start和stop方法,开始和停止
5、完全基于ui线程,因此部分ui相关的操作会在这个计时器内进行
6、长时间的ui操作可能导致部分tick丢失

例如

复制代码 代码如下:
public partial class form1 : form

{
public form1()
{
initializecomponent();
}

int num = 0;

private void form_timer_tick(object sender, eventargs e)
{
label1.text = (++num).tostring();
thread.sleep(3000);
}

private void button1_click(object sender, eventargs e)
{
form_timer.start();
}

private void button2_click(object sender, eventargs e)
{
form_timer.stop();
}
}

实例解析

1、上面这个是一个很简单的功能,在form窗体上拖了一个system.windows.forms.timer控件名字为form_timer,在属性窗中把enable属性设置为ture,interval是定时器的间隔时间。双击这个控件就可以看到 form_timer_tick方法。在这个方法中,我们让她不停的加一个数字并显示在窗体上,2个按钮提供了对计时器的控制功能。
2、执行的时候你去点击其他窗体在回来,你会发现我们的窗体失去响应了。因为我们这里使用thread.sleep(3000);让当前线程挂起,而ui失去相应,说明了这里执行时候采用的是单线程。也就是执行定时器的线程就是ui线程。
3、timer 用于以用户定义的事件间隔触发事件。windows 计时器是为单线程环境设计的,其中,ui 线程用于执行处理。它要求用户代码有一个可用的 ui 消息泵,而且总是在同一个线程中操作,或者将调用封送到另一个线程。
4、在timer内部定义的了一个tick事件,我们前面双击这个控件时实际是增加了一行代码

复制代码 代码如下:
this.form_timer.tick += new system.eventhandler(this.form_timer_tick);

然后windows将这个定时器与调用线程关联(ui线程)。当定时器触发时,windows把一个定时器消息插入到线程消息队列中。调用线程执行一个消息泵提取消息,然后发送到回调方法中(这里的form_timer_tick方法)。而这些都是单线程进行了,所以在执行回调方法时ui会假死。所以使用这个控件不宜执行计算受限或io受限的代码,因为这样容易导致界面假死,而应该使用多线程调用的timer。另外要注意的是这个控件时间精度不高,精度限定为 55 毫秒。

二、system.timers.timer

1. 用的不是tick事件,而是elapsed事件
2. 和system.windows.forms.timer一样,用start和stop方法
3. autoreset属性决定计时器是不是要发起一次事件然后停止,还是进入开始/等待的循环。system.windows.forms.timer没有这个属性
4. 设置对于ui控件的同步对象(synchronizing object),对控件的ui线程发起事件

例如

复制代码 代码如下:
public partial class form1 : form

{
public form1()
{
initializecomponent();
}

int num = 0;
datetime time1 = new datetime();
datetime time2 = new datetime();
//定义timer
system.timers.timer timers_timer = new system.timers.timer();

private void button1_click(object sender, eventargs e)
{
//手动设置timer,开始执行
timers_timer.interval = 20;
timers_timer.enabled = true;
timers_timer.elapsed += new system.timers.elapsedeventhandler(timers_timer_elapsed);
time1 = datetime.now;
}

void timers_timer_elapsed(object sender, system.timers.elapsedeventargs e)
{
label1.text = convert.tostring((++num)); //显示到lable
thread.sleep(3000);
}

private void button2_click(object sender, eventargs e)
{
//停止执行
timers_timer.enabled = false;
time2 = datetime.now;
messagebox.show(convert.tostring(time2-time1));
}
}

三、system.threading.timer

复制代码 代码如下:
public partial class form1 : form
{
public form1()
{
initializecomponent();
}

int num = 0;
datetime time1 = new datetime();
datetime time2 = new datetime();
system.threading.timer thread_time;

private void button1_click(object sender, eventargs e)
{
//启动
thread_time = new system.threading.timer(thread_timer_method,null,0,20);
time1 = datetime.now;

}

void thread_timer_method(object o)
{
label1.text = convert.tostring((++num));
system.threading.thread.sleep(3000);
}

private void button2_click(object sender, eventargs e)
{
//停止
thread_time.dispose();
time2 = datetime.now;
messagebox.show(convert.tostring(time2-time1));
}
}

实例解析

1、用threading.timer时的方法,和前面就不太相同了,所以的参数全部在构造函数中进行了设置,而且可以设置启动时间。而且没有提供start和stop方法来控制计时器。而且是以一种回调方法的方式实现,而不是通过事件来实现的。他们之间还是有区别的。

2、我们只有销毁掉对象来停止他。当你运行时,你会发现他和前面的timers.timer一样,是多线程的,主要表现在不会假死,调试运行报错。但跟让你奇怪的是,我们的代码竟然无法让她停止下来。调用了dispose方法没有用。问题在那?然后有进行了测试,修改了间隔时间为100,200,500,1000,3000,4000。这几种情况。发现当间隔为500ms以上是基本马上就停止了。而间隔时间相对执行时间越短,继续执行的时间越长。这应该是在间隔时间小于执行时间时多个线程运行造成的。因为所有的线程不是同时停止的。间隔越短,线程越多,所以执行次数越多。

3、system.threading.timer 是一个简单的轻量计时器,它使用回调方法并由线程池线程提供服务。不建议将其用于 windows 窗体,因为其回调不在用户界面线程上进行。

希望本文所述对大家的c#程序设计有所帮助。

上一篇:

下一篇: