网站首页 > 技术文章 正文
定时器是软件开发中至关重要的组件,可以在特定时间间隔内执行任务。在本文中,我将探讨如何在C#中创建一个自定义定时器,它不仅提供定时器的基本功能,还包括防止重入和监视执行时间等功能。定时器名字不知道取啥好,就叫AppTimer吧!
AppTimer类属性和事件
AppTimer类包括几个属性和事件:
- ElapsedHandler:表示定时器到期时要执行的操作的事件。
- ExceptionHandler:处理定时器执行过程中的异常的事件。
- Period:表示定时器应该到期的间隔时间的整数属性(以毫秒为单位)。
- RunOnStart:一个布尔属性,指示定时器是否在实例化时立即启动。
- Name:用于指定定时器名称的字符串属性。
- OpenDiagnostics:一个布尔属性,确定是否启用性能诊断。
实现细节
- _taskTimer:Timer类的实例,用于安排定时器事件。
- _performingTasks:一个易失性布尔标志,指示定时器当前是否正在执行任务。
- _isRunning:一个易失性布尔标志,指示定时器是否处于活动状态。
- sw:用于性能监控的Stopwatch实例。
构造函数和初始化
该类提供了两个构造函数。默认构造函数使用默认值初始化_taskTimer。第二个构造函数允许指定定时器的名称、周期和其他可选参数。
Start方法
Start方法启动定时器,确保周期有效,然后启动定时器。它还包括一个CancellationToken参数,以支持取消定时器。
主要特点
防止重入
为了防止重入,使用_performingTasks标志来指示定时器当前是否正在执行任务。这确保了在先前的任务仍在运行时,定时器不会启动新任务。
监视执行时间
OpenDiagnostics属性允许启用性能诊断。当设置为true时,定时器利用Stopwatch来测量任务的执行时间。
完整代码
/// <summary>
/// 应用定时器
/// 定时器主要功能有:防止重入,监控执行时间
/// </summary>
public class AppTimer : IDisposable
{
/// <summary>
/// 定时器执行的业务处理.
/// </summary>
public event EventHandler ElapsedHandler;
/// <summary>
/// 异常处理
/// </summary>
public event EventHandler<Exception> ExceptionHandler;
/// <summary>
/// 间隔时间(单位毫秒).
/// </summary>
public int Period { get; set; }
/// <summary>
/// 启动就开始.
/// </summary>
public bool RunOnStart { get; set; }
/// <summary>
/// 定时器名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 是否开启性能诊断
/// </summary>
public bool OpenDiagnostics { get; set; }
private readonly Timer _taskTimer; //定时器
private volatile bool _performingTasks; // 当前定时器是否正在执行任务
private volatile bool _isRunning; // 定时器是否运行
private Stopwatch sw; // 性能整顿
public AppTimer()
{
_taskTimer = new Timer(TimerCallBack, null, Timeout.Infinite, Timeout.Infinite);
}
public AppTimer(string name, int period, bool isRunontart = false, bool openDiagnostics = true) : this()
{
Name = name;
Period = period;
RunOnStart = isRunontart;
OpenDiagnostics = openDiagnostics;
}
public void Start(CancellationToken cancellationToken = default)
{
if (Period <= 0)
{
throw new Exception("Period 必须赋值");
}
lock (_taskTimer)
{
_taskTimer.Change(RunOnStart ? 0 : Period, Timeout.Infinite);
_isRunning = true;
}
}
public void Stop(CancellationToken cancellationToken = default)
{
lock (_taskTimer)
{
_taskTimer.Change(Timeout.Infinite, Timeout.Infinite);
while (_performingTasks)
{
Monitor.Wait(_taskTimer);
}
_isRunning = false;
}
}
private void TimerCallBack(object state)
{
if (ElapsedHandler == null)
{
return;
}
lock (_taskTimer)
{
if (!_isRunning || _performingTasks)
{
return;
}
_taskTimer.Change(Timeout.Infinite, Timeout.Infinite);
_performingTasks = true;
}
if (OpenDiagnostics)
{
sw = Stopwatch.StartNew();
}
try
{
ElapsedHandler.Invoke(this, new EventArgs());
}
catch(Exception ex)
{
ExceptionHandler.Invoke(this, ex);
}
finally
{
lock (_taskTimer)
{
_performingTasks = false;
if (_isRunning)
{
_taskTimer.Change(Period, Timeout.Infinite);
}
Monitor.Pulse(_taskTimer);
}
if (OpenDiagnostics)
{
sw.Stop();
Console.WriteLine(#34;定时器:“{Name}”执行完成,总用时:{sw.ElapsedMilliseconds}毫秒");
}
}
}
public void Dispose()
{
_taskTimer?.Dispose();
}
}
测试代码
var time = new AppTimer("test",2000);
time.ElapsedHandler += Time_ElapsedHandler;
time.ExceptionHandler += Time_ExceptionHandler;
time.Start();
private static void Time_ExceptionHandler(object sender, Exception ex)
{
Console.WriteLine(#34;{DateTime.Now.ToString("HH:mm:ss fff")}发生了异常了:" + ex.Message);
}
private static void Time_ElapsedHandler(object sender, EventArgs e)
{
var random = new Random();
var a = random.Next(0, 100);
if (a % 5 == 0)
{
throw new Exception("我是个异常!!!!!");
}
if (a % 3 == 0)
{
Console.WriteLine(#34;{DateTime.Now.ToString("HH:mm:ss fff")}我是个大任务,预计5s完成");
Thread.Sleep(5000);
}
else
{
Console.WriteLine(#34;{DateTime.Now.ToString("HH:mm:ss fff")}我是个小任务,预计0.2s完成");
Thread.Sleep(200);
}
}
测试结果
结论
在本文中,我们探讨了在C#中实现自定义定时器的方法,其中包括防止重入和监视执行时间等重要功能。当然代码还可以扩展,比如增加整个应用定时器统计和监控,实时监控定时器运行状态。
猜你喜欢
- 2024-09-11 C# (Winform)实现USB HID自定义接口操作(控制下位机,如STM32)
- 2024-09-11 Tcp服务端一直sleep,客户端不断发送数据产生的问题
- 2024-09-11 C#中的进程与线程及其并发编程(c#多线程并发处理)
- 2024-09-11 在服务中默默地执行C#业务代码(在服务中默默地执行c#业务代码)
- 2024-09-11 C#中AutoResetEvent和ManualResetEvent使用场景
- 2024-09-11 C# AutoResetEvent 和 ManualResetEvent 在 WinForms 应用中的使用
- 2024-09-11 C#基础 DateTime详解(c# datetime.date)
- 2024-09-11 C# 面向对象 静态类和静态成员(c# 静态方法和实例方法)
- 2024-09-11 C#编程中如何使用线程(c#线程是什么)
- 2024-09-11 一篇文章搞懂C#中的接口(c#中接口怎么使用)
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)