Timer usage in C # and resolving re-entry issues

Source: Internet
Author: User
Tags net thread

★ Preface

Open long-Lost live Writer, and has not written a blog, really lazy. Nonsense not much to say, directly into the theme of this blog--timer. Why write this, because a few days ago invited friends, want to be a "hacker" gadget, the function is very simple is to automatically get the contents of the Clipboard and then send the message, you need to use a timer to loop the contents of the Clipboard, but due to the ability to send mail, using C # SmtpClient Always Send mail, previously written similar to the function of e-mail, at that time can use NetEase, now also can not use, do not know how, had to forget. I encountered a problem that I didn't think about before using the timer--re-entry.

★ Introduction

First of all, a brief introduction to the timer, which is referred to as the timer refers to the System.Timers.timer, as the name implies, can be at the specified interval is the event raised. The official introduction here, excerpt as follows:

The timer component is a server-based timer that enables you to specify the periodic interval at which the Elapsed event is raised in the application. You can then provide general processing by handling this event. For example, suppose you have a critical server that must remain operational 24 hours a day, 7 days a week. You can create a service that uses a Timer to periodically check the server and ensure that the system is turned on and running. If the system does not respond, the service can attempt to restart the server or notify the administrator.    Server-based Timer is designed for use with worker threads in a multithreaded environment. Server timers can move between threads to handle the Elapsed event that is raised, which can cause events to be raised more accurately on time than the Windows timer.

If you want to know what the difference with other timer, you can see here, there is a detailed introduction, no longer say (in fact, I do not know that there are so many). What's the advantage of using this timer? Mainly because it is implemented through the. NET Thread pool, lightweight, accurate timing, no special requirements for applications and messages.

★ Use

Here is a brief introduction, this timer is how to use, in fact, it is very simple, I use the example provided by Microsoft to test, directly on the code:

   //timer is not declared as a local variable, otherwise it will be recycled by GC    Private StaticSystem.Timers.Timer Atimer;  Public Static voidMain () {//instantiate the Timer class, set a time interval of 10000 milliseconds;Atimer =NewSystem.Timers.Timer (10000); //Registering events for Timersatimer.elapsed + =NewElapsedeventhandler (ontimedevent); //set the interval to 2 seconds (2000 milliseconds), overriding the intervals at which the constructor is setAtimer.interval = -; //Whether the setting is executed once (false) or always (true), the default is TrueAtimer.autoreset =true; //Start Timingatimer.enabled =true; Console.WriteLine ("Press any key to exit the program. ");    Console.ReadLine (); }    //specify events triggered by the timer    Private Static voidOntimedevent (Objectsource, Elapsedeventargs E) {Console.WriteLine ("the event that is triggered occurs in: {0}", E.signaltime); }

The result of the operation is as follows, the timing is quite accurate:

/* Press any key to exit the program. The event that is triggered occurs in: 2014/12/26 Friday 23:08:51 The event that is triggered occurs in: 2014/12/26 Friday 23:08:53 The event that is triggered occurs in: 2014/12/26 Friday 23:08:55 event occurred in: 2014/12/26 star Period five 23:08:57 the event that is triggered occurs in: 2014/12/26 Friday 23:08:59* /
★ Re-entry problem recurrence and analysis

What do you mean, re-entry? This is a concept about multithreaded programming: In a program, when multiple threads are running concurrently, it is possible that the same method is being called simultaneously by multiple processes. When there are some non-thread-safe code in this method, the method re-entry causes inconsistent data. Timer method re-entry refers to the use of multi-threaded timers, a timer processing is not completed, to the time, another timer will continue to enter the method for processing. Here's a demonstration of the re-entry problem (which may not be very good to reproduce, but it's a simple matter to explain):

    //static members that are used to cause thread synchronization problems    Private Static intOutPut =1; //number of times, the timer did not adjust the method self-increment 1    Private Static intnum =0; Private StaticSystem.Timers.Timer Timer =NewSystem.Timers.Timer ();  Public Static voidMain () {timer. Interval= +; Timer. Elapsed+=Timerstimerhandler; Timer.        Start (); Console.WriteLine ("Press any key to exit the program. ");    Console.ReadLine (); }    /// <summary>    ///callback method for System.Timers.Timer/// </summary>    /// <param name= "Sender" ></param>    /// <param name= "args" ></param>    Private Static voidTimerstimerhandler (Objectsender, EventArgs args) {        intT = + +num; Console.WriteLine (string. Format ("Thread {0} output: {1}, Output time: {2}", T, Output.tostring (), DateTime.Now)); System.Threading.Thread.Sleep ( -); OutPut++; Console.WriteLine (string. Format ("Thread {0} self-increment 1 output: {1}, Output time: {2}", T, Output.tostring (), DateTime.Now)); }

The output is shown below:

does it feel like the output above is strange, The first is the thread 1 output is 1, there is no problem, and then 2 seconds after the thread 1 from 1 after the output of 2, this is a problem, why the middle of the output of thread 2? It is even more strange that the thread 2 has just begun to output 1, since the increase of 1 altogether becomes 3! In fact, this is the problem caused by re-entry. Don't worry, we'll know the reason for the analysis.

First timer start time, open a thread 1 execution method, when thread 1 first output, then thread 1 sleeps 2 seconds, at this time the timer is not idle, because the timer interval is 1 seconds, when the thread 1 sleep 1 seconds later, the timer again opened the Threads 2 execution method, Thread 2 is not a pipeline 1 is in the execution or hibernation, so at this point the output of thread 2 is also 1, because thread 1 is still dormant, and there is no self-increment. Then another 1 seconds, then occurred at the same time two events, thread 1 over the sleep state self-increment output for 2,timer at the same time to open a thread 3, thread 3 output is thread 1 since the increment of the value of 2, and 1 seconds, thread 2 over the sleep state, the previous output is 2, so the output is 3 after the increment, It's been 1 seconds. I'm almost dizzy, that's probably the point, I want to express is: a timer to open the thread processing has not finished, to the time, another timer will continue to enter the method for processing.

So how do you solve this problem? There are three solutions, the following one by one ways to adapt to different scenarios, but still recommend the last one, more secure.

★ Re-entry Problem solving solution

1, the use of Lock (Object) method to prevent re-entry, indicating that a timer processing is executing, the next timer occurs when the last one is not executed to wait for execution, the application of the re-entry of the rare occurrence of the scene (specifically did not study, may be compared to the memory bar).

The code is similar to the above, adding lock to the triggering method, so that when thread 2 enters the triggering method, it finds that it has been locked, waits for the code in the lock to finish executing, and the code is as follows:

Private Static ObjectLocko =New Object(); /// <summary>     ///callback method for System.Timers.Timer/// </summary>    /// <param name= "Sender" ></param>    /// <param name= "args" ></param>    Private Static voidTimerstimerhandler (Objectsender, EventArgs args) {
        int t = + +
lock (Locko)
        {            Console.WriteLine (string. Format (" thread {0} output: {1},       output time: {2}", T, Output.tostring (), DateTime.Now));            System.Threading.Thread.Sleep (+);            OutPut+ +;            Console.WriteLine (string. Format (" thread {0} self-increment 1 output: {1}, Output time: {2}", T, Output.tostring (), DateTime.Now));        }    }

Execution Result:

2, set a flag, indicating that a timer processing is executing, the next timer occurs when the last one did not finish to give up ( Note here is to give up, rather than wait oh, see the results of the implementation to understand what meaning ), Suitable for re-entry of frequently occurring scenarios. The code is as follows:

Private Static intIntimer =0; /// <summary>    ///callback method for System.Timers.Timer/// </summary>    /// <param name= "Sender" ></param>    /// <param name= "args" ></param>    Private Static voidTimerstimerhandler (Objectsender, EventArgs args) {        intT = + +num; if(Intimer = =0) {Intimer=1; Console.WriteLine (string. Format ("Thread {0} output: {1}, Output time: {2}", T, Output.tostring (), DateTime.Now)); System.Threading.Thread.Sleep ( -); OutPut++; Console.WriteLine (string. Format ("Thread {0} self-increment 1 output: {1}, Output time: {2}", T, Output.tostring (), DateTime.Now)); Intimer=0; }    }

Execution Result:

3, in the multi-thread to give Intimer assignment is not safe, Interlocked.exchange provides a lightweight thread-safe method of assigning objects (feeling higher than the larger, is a more recommended method), the execution results and Method 2, is also abandoned Perform. Interlocked.exchange Usage Reference here .

Private Static intIntimer =0; /// <summary>    ///callback method for System.Timers.Timer/// </summary>    /// <param name= "Sender" ></param>    /// <param name= "args" ></param>    Private Static voidTimerstimerhandler (Objectsender, EventArgs args) {        intT = + +num; if(Interlocked.exchange (refIntimer,1) ==0) {Console.WriteLine (string. Format ("Thread {0} output: {1}, Output time: {2}", T, Output.tostring (), DateTime.Now)); System.Threading.Thread.Sleep ( -); OutPut++; Console.WriteLine (string. Format ("Thread {0} self-increment 1 output: {1}, Output time: {2}", T, Output.tostring (), DateTime.Now)); Interlocked.exchange (refIntimer,0); }    }

Execution Result:

★ Summary

finally code finished word, really not easy ah. Blogging is a very energy-consuming thing, sincerely admire those Daniel his pen, salute! Here a little summary, the timer is a very simple use of the class, take it, here is the main summary of the use of the timer when the problem of re-entry, not previously thought of this problem, the solution is quite simple, here are listed three kinds, the main reference here , Don't know if there's any other way. The solution here also applies multi-threaded re-entry issues. It's not too early to wash and sleep.

★ Reference

Here is a list of references not mentioned in the article, thank you for the wisdom of the predecessors of the crystallization!

Asp. NET----The re-entry of the timer callback method

Timer usage in C # and resolving re-entry issues

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.