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

详解C#中的定时器Timer类及其垃圾回收机制

程序员文章站 2023-11-14 20:30:10
关于c# timer类  在c#里关于定时器类就有3个 c# timer使用的方法1.定义在system.windows.forms里 c# timer使用的...

关于c# timer类  在c#里关于定时器类就有3个

c# timer使用的方法1.定义在system.windows.forms里

c# timer使用的方法2.定义在system.threading.timer类里  "

c# timer使用的方法3.定义在system.timers.timer类里

下面我们来具体看看这3种c# timer用法的解释:

(1)system.windows.forms.timer

应用于winform中的,它是通过windows消息机制实现的,类似于vb或delphi中的timer控件,内部使用api  settimer实现的。它的主要缺点是计时不精确,而且必须有消息循环,console  application(控制台应用程序)无法使用。  
 
(2)system.timers.timer

和system.threading.timer非常类似,它们是通过.net  thread  pool实现的,轻量,计时精确,对应用程序、消息没有特别的要求。

(3)system.timers.timer还可以应用于winform,完全取代上面的timer控件。它们的缺点是不支持直接的拖放,需要手工编码。

c# timer用法实例

使用system.timers.timer类

system.timers.timer t =  
new system.timers.timer(10000); 
//实例化timer类,设置间隔时间为10000毫秒;  
t.elapsed +=  
new system.timers.elapsedeventhandler(theout); 
//到达时间的时候执行事件;  
t.autoreset = true; 
//设置是执行一次(false)还是一直执行(true);  
t.enabled = true; 
//是否执行system.timers.timer.elapsed事件;  
 
public void theout( 
object source,  
system.timers.elapsedeventargs e)  
 {  
  messagebox.show("ok!");  
 } 

 
timer的垃圾回收机制
通常我们需要定时执行一段任务的时候,我们就需要定时器,这时我们就可以使用c# system.threading空间中的 timer定时器;他是个异步定时器,时间到时每次都是在线程池中分配一个线程去执行任务。下面我们来看一个有趣的例子:

class program
  {
    static void main(string[] args)
    {
      timer timer = new timer(timercallback,null,0,2000);
      
      console.readline();
    }
 
    private static void timercallback(object o)
    {
      console.writeline("in timercallback method");
      gc.collect();
 
      
    }
  }

当我们在debug模式下运行该段程序时,正如我们期盼的那样程序会每隔2秒钟执行该方法,打印出"in timercallback method”,而在release模式下执行的时候,只执行一次该方法,字符串只打印一次。在这里我们在调用timercallback方法时,强制执行垃圾回收器,说明在release模式下,垃圾回收器执行回收算法时,首先假设所有对象都是可回收的,当将timer对象赋值给变量t后,t没有在被引用,因此也就没有变量引用timer对象,所以垃圾收集这时会回收timer对象。那么为什么在debug模式下却能够运行能,这跟c#编译器的优化方式有关,在release模式下编译器做了相关的优化操作。而在debug模式下,timer对象的生成期是方法的结束,这样做也是为了调试的方便。要不然在调试时,我们执行到timer timer = new timer()后想看timer的值时,已经被垃圾回收器给回收了,这是我们不期望看到的结果,编译器如何处理的,我们可以看看编译器在release模式下和debug模式下对上面的代码编译后生成的il对比我们既知结果。

release模式编译生成的il:

.method private hidebysig static void main(string[] args) cil managed
{
 .entrypoint
 // code size    32 (0x20)
 .maxstack 8
 il_0000: ldnull
 il_0001: ldftn   void gctest.program::timercallback(object)
 il_0007: newobj   instance void [mscorlib]system.threading.timercallback::.ctor(object,
                                           native int)
 il_000c: ldnull
 il_000d: ldc.i4.0
 il_000e: ldc.i4   0x7d0
 il_0013: newobj   instance void [mscorlib]system.threading.timer::.ctor(class [mscorlib]system.threading.timercallback,
                                       object,
                                       int32,
                                       int32)
 il_0018: pop
 il_0019: call    string [mscorlib]system.console::readline()
 il_001e: pop
 il_001f: ret
} // end of method program::main

debug模式下生成的il:

method private hidebysig static void main(string[] args) cil managed
{
 .entrypoint
 // code size    33 (0x21)
 .maxstack 4
 .locals init ([0] class [mscorlib]system.threading.timer timer)
 il_0000: nop
 il_0001: ldnull
 il_0002: ldftn   void gctest.program::timercallback(object)
 il_0008: newobj   instance void [mscorlib]system.threading.timercallback::.ctor(object,
                                           native int)
 il_000d: ldnull
 il_000e: ldc.i4.0
 il_000f: ldc.i4   0x7d0
 il_0014: newobj   instance void [mscorlib]system.threading.timer::.ctor(class [mscorlib]system.threading.timercallback,
                                       object,
                                       int32,
                                       int32)
 il_0019: stloc.0
 il_001a: call    string [mscorlib]system.console::readline()
 il_001f: pop
 il_0020: ret
} // end of method program::main

从生成的il中我们可以看出在debug模式下,生成il比在release模式下多了19行红色字体的il指令码,该指令码的作用是将15行生成的引用timer对象的栈上的变量存放到局部变量0中。所以使得在debug模式下该t还被引用,不能够回收timer对象,所以也能出现我们期盼的结果,那么如何在两种模式下都能得到我们期盼的结果呢。我们可以如下操作。

正确的代码:

class program
  {
    static void main(string[] args)
    {
      timer timer = new timer(timercallback,null,0,2000);
    
      console.readline();
      timer.dispose();
    }

    private static void timercallback(object o)
    {
      console.writeline("in timercallback method");

      gc.collect();

      
    }
  }

这时不管是在release模式下还是debug模式下,都会每隔2秒钟调用我们的回调方法。