zoukankan      html  css  js  c++  java
  • System.Threading.Timer使用心得

    System.Threading.Timer 是一个使用回调方法的计时器,而且由线程池线程服务,简单且对资源要求不高。

    "只要在使用 Timer,就必须保留对它的引用。
    "对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。即使 Timer 仍处在活动状态,也会被回收。
    "当不再需要计时器时,请使用 Dispose 方法释放计时器持有的资源。

    使用 TimerCallback 委托指定希望 Timer 执行的方法。计时器委托在构造计时器时指定,并且不能更改。此方法不在创建计时器的线程中执行,而是在系统提供的线程池线程中执行。

    创建计时器时,可以指定在第一次执行方法之前等待的时间量(截止时间)以及此后的执行期间等待的时间量(时间周期)。可以使用 Change 方法更改这些值或禁用计时器。

    Demo application:
    应用场景:在windows form程序自动执行某项工作后,希望其windows form能够自动关闭。

    "代码设计:

    (1)首先声明Timer变量:
    //一定要声明成局部变量以保持对Timer的引用,否则会被垃圾收集器回收!
    private System.Threading.Timer timerClose;

    (2)在上述自动执行代码后面添加如下Timer实例化代码:
    // Create a timer thread and start it
    timerClose = new System.Threading.Timer(new TimerCallback(timerCall), this, 5000, 0);

    //Timer构造函数参数说明:
    Callback:一个 TimerCallback 委托,表示要执行的方法。
    State:一个包含回调方法要使用的信息的对象,或者为空引用(Visual Basic 中为 Nothing)。
    dueTime:调用 callback 之前延迟的时间量(以毫秒为单位)。指定 Timeout.Infinite 以防止计时器开始计时。指定零 (0) 以立即启动计时器。
    Period:调用 callback 的时间间隔(以毫秒为单位)。指定 Timeout.Infinite 可以禁用定期终止。

    (3)定义TimerCallback委托要执行的方法:
    private void timerCall(object obj)
    {
          timerClose.Dispose();
          this.Close();
    }

    当然,除了使用上述System.Threading.Timer类的TimerCallback 委托机制外,应该还有很多其他的办法。
    另外,这里只是demo了TimerCallback委托的简单应用。

    Appendix about the article
    在读一段关于Design Pattern的代码时,看到使用Timer类TimerCallback委托,随并记录下来。

    Reference:
    1, MSDN, System.Threading.Timer class

     (来自:http://hi.baidu.com/murphy1314/blog/item/4c0413b5557c3bc936d3cab9.html)

    推荐:一个实例明白AutoResetEvent和 ManulResetEvent的用法http://xhinker.blog.51cto.com/640011/180377

    AutoResetEvent 允许线程通过发信号互相通信。通常,此通信涉及线程需要独占访问的资源。

    线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。如果 AutoResetEvent 处于非终止状态,则该线程阻塞,并等待当前控制资源的线程
    通过调用 Set 发出资源可用的信号。

    调用 SetAutoResetEvent 发信号以释放等待线程。AutoResetEvent 将保持终止状态,直到一个正在等待的线程被释放,然后自动返回非终止
    状态。如果没有任何线程在等待,则状态将无限期地保持为终止状态。

    可以通过将一个布尔值传递给构造函数来控制 AutoResetEvent 的初始状态,如果初始状态为终止状态,则为 true;否则为 false

    通俗的来讲只有等myResetEven.Set()成功运行后,myResetEven.WaitOne()才能够获得运行机会;Set是发信号,WaitOne是等待信号,只有发了信号,
    等待的才会执行。如果不发的话,WaitOne后面的程序就永远不会执行。下面我们来举一个例子:我去书店买书,当我选中一本书后我会去收费处付钱,
    付好钱后再去仓库取书。这个顺序不能颠倒,我作为主线程,收费处和仓库做两个辅助线程,代码如下:

    using System;
    using System.Linq;
    using System.Activities;
    using System.Activities.Statements;
    using System.Threading;
    
    namespace CaryAREDemo
    {
        class Me
        {
            const int numIterations = 550;
            static AutoResetEvent myResetEvent = new AutoResetEvent(false);
            static AutoResetEvent ChangeEvent = new AutoResetEvent(false);
            //static ManualResetEvent myResetEvent = new ManualResetEvent(false);
            //static ManualResetEvent ChangeEvent = new ManualResetEvent(false);
            static int number; //这是关键资源
    
            static void Main()
            {
                Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc));
                payMoneyThread.Name = "付钱线程";
                Thread getBookThread = new Thread(new ThreadStart(GetBookProc));
                getBookThread.Name = "取书线程";
                payMoneyThread.Start();
                getBookThread.Start();
    
                for (int i = 1; i <= numIterations; i++)
                {
                    Console.WriteLine("买书线程:数量{0}", i);
                    number = i;
                    //Signal that a value has been written.
                    myResetEvent.Set();
                    ChangeEvent.Set();
                    Thread.Sleep(0);
                }
                payMoneyThread.Abort();
                getBookThread.Abort();
            }
    
            static void PayMoneyProc()
            {
                while (true)
                {
                    myResetEvent.WaitOne();
                    //myResetEvent.Reset();
                    Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
                }
            }
            static void GetBookProc()
            {
                while (true)
                {
                    ChangeEvent.WaitOne();
                    // ChangeEvent.Reset();               
                    Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
                    Console.WriteLine("------------------------------------------");
                    Thread.Sleep(0);
                }
            }
        }
    }
    运行结果如下:
    image 

    AutoResetEvent与ManualResetEvent的区别

    他们的用法\声明都很类似,Set方法将信号置为发送状态 Reset方法将信号置为不发送状态WaitOne等待信号的发送。其实,从名字就可以看出一个手动,
    一个自动,这个手动和自动实际指的是在Reset方法的处理上,如下面例子:

    public AutoResetEvent autoevent=new AutoResetEvent(true);
    public ManualResetEvent manualevent=new ManualResetEvent(true);

    默认信号都处于发送状态,

    autoevent.WaitOne();
    manualevent.WaitOne();

    如果 某个线程调用上面该方法,则当信号处于发送状态时,该线程会得到信号,得以继续执行。差别就在调用后,autoevent.WaitOne()每次只允许一个线程
    进入,当某个线程得到信号(也就是有其他线程调用了autoevent.Set()方法后)后,autoevent会自动又将信号置为不发送状态,则其他调用WaitOne的线程只
    有继续等待.也就是说,autoevent一次只唤醒一个线程。而manualevent则可以唤醒多个线程,因为当某个线程调用了set方法后,其他调用waitone的线程
    获得信号得以继续执行,而manualevent不会自动将信号置为不发送.也就是说,除非手工调用了manualevent.Reset().方法,则manualevent将一直保持有信号状态,manualevent也就可以同时唤醒多个线程继续执行。如果上面的程序换成ManualResetEvent的话,就需要在waitone后面做下reset。

    来自:http://www.cnblogs.com/carysun/archive/2009/10/29/autoresetevent.html

    今天在看一段DEMO代码的时候发现AutoResetEvent被反复用到,在MSND中查了资料同时到在网上搜到了一个很简短的例子,这个例子帮我理解AutoResetEvent的用法起了不少辅助作用,这里贴出来,希望对大家理解有所帮助:
    (代码都已经在VS2005中成功调试通过,注释是我的理解,只能起参考作用,呵呵)

    using System;
    using System.Threading;

    namespace AutoResetEvent_Examples
    {
        class MyMainClass
        {
            //初始的时候是没有信号的,这里的意思是指参数false
            const int numIterations = 100; //重复次数设置多少都无所谓,为让大家看清楚设置了100
            static AutoResetEvent myResetEvent = new AutoResetEvent(false);
            static int number;

            static void Main()
            {
                //创建并开始一个线程。
                Thread myReaderThread = new Thread(new ThreadStart(MyReadThreadProc));
                myReaderThread.Name = "ReaderThread";
                myReaderThread.Start();

                for (int i = 1; i <= numIterations; i++)
                {
                    Console.WriteLine("Writer thread writing value: {0}", i);
                    number = i;

                    //发信号,说明值已经被写进去了。这里的意思是说Set是一个发信号的方法。
                   myResetEvent.Set();

                    //让每次循环当中有些间隔,没有其他作用,可以注释掉
                  Thread.Sleep(1000);
                }

                //终止阅读线程。

                myReaderThread.Abort();
            }

            static void MyReadThreadProc()
            {
                while (true)
                {
                    //在数据被作者写入之前不会被读者读取
                    //在上次读取之前至少有一次。
                    myResetEvent.WaitOne();
                    Console.WriteLine("{0} reading value: {1}", Thread.CurrentThread.Name, number);
                }
            }
        }
    }

    下面我会配图进行说明,便于大家更好的理解,AutoResetEvent在使用前必须通过是例化进行初始,如:
    AutoResetEvent myResetEvent = new AutoResetEvent(false);
    MSDN中讲到,若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false
    小女子的理解:如过设置true,也就是说这个Event回自动Reset,那么myResetEvent.WaitOne()就能够在程序一启动就获得运行权;就相当于一启动程序就自动运行了一次myResetEven.Set();
    反之,就要等myResetEven.Set()成功运行后,myResetEven.WaitOne()才能够获得运行机会;

    这里我做个实验给大家看,大家会看到,在设置为true的时候会首先看到ReaderThread reading value运行,然后才是Writer thread wrirting出现:

    如设置为false就会发现,先出现的是写的信息:

    相信大家应该明白它的初始的意义了.
    上面我们提到了myResetEven.Set(),这个方法是做什么的呢,其实简单点说就相当于一个开关,如果没有执行set()方法,下面的waitOne()就等不到让它执行的通知,这样一来waitOne后面的语句也不会执行了,waitone()就会傻等下去...一直等到set()执行后才会执行它后面的操作,

    我们再次做个实验,把myResetEven.Set()注释掉,结果应该是读的信息永远不会出现,如图:


    果然和我们预料的一样,只有写的信息被执行.

    综合起来理解应该是这样,AutoResetEvent提供了一个类似于条件判断的开关来控制线程,
    if( )
    {
    ......

    }

    也就是说,如果 AutoResetEvent.Set()上面的线程完全被执行,AutoResetEvent.WaitOne()控制下的线程才被执行.很简单吧!!

    也不知道小女子表达清查了没有,如果有不清楚欢迎交流!

    来自:http://hi.baidu.com/iaskall/blog/item/1938e00045f87012738b6526.html

  • 相关阅读:
    Benelux Algorithm Programming Contest 2016 Preliminary K. Translators’ Dinner(思路)
    Benelux Algorithm Programming Contest 2016 Preliminary Target Practice
    Benelux Algorithm Programming Contest 2016 Preliminary I. Rock Band
    Benelux Algorithm Programming Contest 2016 Preliminary A. Block Game
    ICPC Northeastern European Regional Contest 2019 Apprentice Learning Trajectory
    ICPC Northeastern European Regional Contest 2019 Key Storage
    2018 ACM ICPC Asia Regional
    2018 ACM ICPC Asia Regional
    Mybatis入库出现异常后,如何捕捉异常
    优雅停止 SpringBoot 服务,拒绝 kill -9 暴力停止
  • 原文地址:https://www.cnblogs.com/Godblessyou/p/2167206.html
Copyright © 2011-2022 走看看