Recently, I used Timer to step on a trap. I 'd like to share it with you to avoid others from continuing to step on.

Source: Internet
Author: User

[Switch] recently I used Timer to step on a pitfall. I 'd like to share it with you to prevent others from continuing to step on it.

[Switch] recently I used Timer to step on a hole and shared it to avoid others from continuing to step on it.

 

Recently, in a small project, there is a scheduled service in the project, which needs to regularly send data to the other party. The time interval is 1.5 s. Then we thought of using the Timer class of C #. We know that Timer

It is really easy to use, because there is a very user-friendly start and stop functions, there is an Interval in the Timer, is used to set the time Interval, and then the time Interval will touch

To send an Elapsed event, we only need to register the callback function to this event. If Interval is reached, it will trigger Elapsed. It seems that everything looks natural,

Note that the callback function itself also takes time to execute. Maybe this time is 1 s, 2 s, or longer, but the timer class does not care about this. It only needs to trigger it for 1.1 s.

Elapsed, which causes my callback to be not executed yet, And the next callback is executed again, which leads to the failure to achieve the expected 5s effect and the appearance

A very serious problem is the thread surge, which is terrible.

 

The following is an example. To simplify the process, I define a task. Of course, Multiple task tasks run together in the project.

 

I. Problem generation

For higher flexibility, I have defined a CustomTimer class that inherits from Timer, and then some data can be stored in the Task to be run. Here we define a Queue.

1 namespace Sample 2 {3 class Program 4 {5 static void Main (string [] args) 6 {7 TimerCustom timer = new TimerCustom (); 8 9 timer. interval = 1500; 10 11 timer. elapsed + = (obj, evt) => 12 {13 TimerCustom singleTimer = obj as TimerCustom; 14 15 if (singleTimer! = Null) 16 {17 if (singleTimer. queue. Count! = 0) 18 {19 var item = singleTimer. queue. dequeue (); 20 21 Send (item); 22} 23} 24}; 25 26 timer. start (); 27 28 Console. read (); 29} 30 31 static void Send (int obj) 32 {33 // random tentative 8-10s34 Thread. sleep (new Random (). next (8000,100 00); 35 36 Console. writeLine ("Current Time: {0}, scheduled data is sent successfully! ", DateTime. now); 37} 38} 39 40 class TimerCustom: System. timers. timer41 {42 public Queue <int> queue = new Queue <int> (); 43 44 public TimerCustom () 45 {46 for (int I = 0; I <short. maxValue; I ++) 47 {48 queue. enqueue (I); 49} 50} 51} 52}

 

Ii. Solution

1. from the perspective, there are already 14 threads in the case of a task, and two threads are executed at the same time in 21s, my first response is how to execute callback later.

The thread is kicked out, that is, to ensure that only two threads are currently using callback, one is being executed, and the other is waiting for execution. If the callback of the first thread is not completed, the third thread will be followed.

Thread, I will directly kick the third thread out until the first callback is executed, so that the third thread can come in and wait for the callback to be executed, then the second thread was opened today.

Start to execute callback, and so on...

Then I thought of using the lock mechanism. I added the lockMe, lockNum, and isFirst fields to customTimer and used lockMe to lock them. I used lockNum to kick unnecessary calls to execute callback.

IsFirst is used to determine whether to execute the callback for the first time. The subsequent callback thread must wait for 1.5s before execution.

1 namespace Sample 2 {3 class Program 4 {5 static void Main (string [] args) 6 {7 TimerCustom timer = new TimerCustom (); 8 9 timer. interval = 1500; 10 11 timer. elapsed + = (obj, evt) => 12 {13 TimerCustom singleTimer = obj as TimerCustom; 14 15 if (singleTimer! = Null) 16 {17 // if the current waiting thread is greater than 2, kill this thread 18 if (Interlocked. read (ref singleTimer. lockNum)> 2) 19 return; 20 21 Interlocked. increment (ref singleTimer. lockNum); 22 23 // here the lock can only have one thread waiting for 24 lock (singleTimer. lockMe) 25 {26 if (! SingleTimer. isFirst) 27 {28 Thread. Sleep (int) singleTimer. Interval); 29} 30 31 singleTimer. isFirst = false; 32 33 if (singleTimer. queue. Count! = 0) 34 {35 var item = singleTimer. queue. dequeue (); 36 37 Send (item); 38 39 Interlocked. decrement (ref singleTimer. lockNum); 40} 41} 42} 43}; 44 45 timer. start (); 46 47 Console. read (); 48} 49 50 static void Send (int obj) 51 {52 Thread. sleep (new Random (). next (8000,100 00); 53 54 Console. writeLine ("Current Time: {0}, email sent successfully! ", DateTime. now); 55} 56} 57 58 class TimerCustom: System. timers. timer59 {60 public Queue <int> queue = new Queue <int> (); 61 62 public object lockMe = new object (); 63 64 public bool isFirst = true; 65 66 /// <summary> 67 // to ensure consistency, two 68 /// locks by default </summary> 69 public long lockNum = 0; 70 71 public TimerCustom () 72 {73 for (int I = 0; I <short. maxValue; I ++) 74 {75 queue. enqueue (I); 76} 77} 78} 79}

 

 

It can be seen that there are no repeated tasks sent in the same second, And the thread is also squashed. At first glance, the effect is not very obvious, but this is in the case of a task.

In the following scenario, the more tasks, the more obvious it is, so this will achieve the effect I want.

 

2. From the above solution, our thinking has been restrained by the problem. At that time, I did the same. After all, we had to fill in the problem. Since there is a thread in callback

Of course I want to control the congestion. In fact, there is nothing wrong with it. When the problem is solved, let's look back, we will find that the Timer class mentioned at the beginning of this article has powerful Stop and

Start function, so .... In this case, the thinking jumps out. Why not turn off the Timer when the callback is executed, and enable the Timer after the callback is executed?

Can the problem be solved? Okay, just do it.

1 namespace Sample 2 {3 class Program 4 {5 static void Main (string [] args) 6 {7 TimerCustom timer = new TimerCustom (); 8 9 timer. interval = 1500; 10 11 timer. elapsed + = (obj, evt) => 12 {13 TimerCustom singleTimer = obj as TimerCustom; 14 15 // stop 16 singleTimer. stop (); 17 18 if (singleTimer! = Null) 19 {20 if (singleTimer. queue. Count! = 0) 21 {22 var item = singleTimer. queue. dequeue (); 23 24 Send (item); 25 26 // enable 27 singleTimer after the message is sent. start (); 28} 29} 30}; 31 32 timer. start (); 33 34 Console. read (); 35} 36 37 static void Send (int obj) 38 {39 Thread. sleep (new Random (). next (8000,100 00); 40 41 Console. writeLine ("Current Time: {0}, email sent successfully! ", DateTime. now); 42} 43} 44 45 class TimerCustom: System. timers. timer46 {47 public Queue <int> queue = new Queue <int> (); 48 49 public object lockMe = new object (); 50 51 // <summary> 52 // to ensure consistency, two 53 /// </summary> 54 public long lockNum = 0 by default; 55 56 public TimerCustom () 57 {58 for (int I = 0; I <short. maxValue; I ++) 59 {60 queue. enqueue (I); 61} 62} 63} 64}

 

As you can see, the problem is also solved, which is simpler and more subtle.


Finally, I would like to conclude that it is very important to think about solving the problem, but it would be very rare to think about it at a higher abstract level...

 

Related Article

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.