-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathTimer.cs
128 lines (109 loc) · 3.32 KB
/
Timer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using System;
using System.Diagnostics;
using System.Threading;
namespace LoLSharp.Modules
{
class Timer
{
public static readonly double TickLength = 1000f / Stopwatch.Frequency;
public static readonly double Frequency = Stopwatch.Frequency;
public static bool IsHighResolution = Stopwatch.IsHighResolution;
public event EventHandler<TimerElapsedEventArgs> Elapsed;
private volatile float _interval;
private volatile bool _isRunning;
private Thread _thread;
public Timer() : this(1f)
{
}
public Timer(float interval)
{
Interval = interval;
}
public float Interval
{
get => _interval;
set
{
if (value < 0f || Single.IsNaN(value))
{
throw new ArgumentOutOfRangeException(nameof(value));
}
_interval = value;
}
}
public bool IsRunning => _isRunning;
public bool UseHighPriorityThread { get; set; } = false;
public void Start()
{
if (_isRunning) return;
_isRunning = true;
_thread = new Thread(ExecuteTimer)
{
IsBackground = true,
};
if (UseHighPriorityThread)
{
_thread.Priority = ThreadPriority.Highest;
}
_thread.Start();
}
public void Stop(bool joinThread = true)
{
_isRunning = false;
if (joinThread && Thread.CurrentThread != _thread)
{
_thread.Join();
}
}
private void ExecuteTimer()
{
float nextTrigger = 0f;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (_isRunning)
{
nextTrigger += _interval;
double elapsed;
while (true)
{
elapsed = ElapsedHiRes(stopwatch);
double diff = nextTrigger - elapsed;
if (diff <= 0f)
break;
if (diff < 1f)
Thread.SpinWait(10);
else if (diff < 5f)
Thread.SpinWait(100);
else if (diff < 15f)
Thread.Sleep(1);
else
Thread.Sleep(10);
if (!_isRunning)
return;
}
double delay = elapsed - nextTrigger;
Elapsed?.Invoke(this, new TimerElapsedEventArgs(delay));
if (!_isRunning)
return;
if (stopwatch.Elapsed.TotalHours >= 1d)
{
stopwatch.Restart();
nextTrigger = 0f;
}
}
stopwatch.Stop();
}
private static double ElapsedHiRes(Stopwatch stopwatch)
{
return stopwatch.ElapsedTicks * TickLength;
}
}
internal class TimerElapsedEventArgs : EventArgs
{
public double Delay { get; }
internal TimerElapsedEventArgs(double delay)
{
Delay = delay;
}
}
}