C# 使用计时器处理类的正确方法是什么?
假设我有一个类,它有一个计时器对象,它不做任何重要的工作——只是一些GUI工作。假设有两种情况,计时器每5分钟消失一次:C# 使用计时器处理类的正确方法是什么?,c#,.net,vb.net,timer,C#,.net,Vb.net,Timer,假设我有一个类,它有一个计时器对象,它不做任何重要的工作——只是一些GUI工作。假设有两种情况,计时器每5分钟消失一次: 在Timer\u expressed委托中,有许多工作要做,需要2分钟才能完成 在Timer\u expressed委托中,几乎没有要做的工作,需要几毫秒才能完成 处理对象和计时器的正确方法是什么?事件委托运行的计时器\u经过的时间长度是否会影响您关于如何正确处置的决定 对此有多种方法,正如Alex在评论中所说,这取决于代理将使用的对象是否也被处理 假设我们有一个“最坏情况”
Timer\u expressed
委托中,有许多工作要做,需要2分钟才能完成李>
Timer\u expressed
委托中,几乎没有要做的工作,需要几毫秒才能完成处理对象和计时器的正确方法是什么?事件委托运行的
计时器\u经过的时间长度是否会影响您关于如何正确处置的决定 对此有多种方法,正如Alex在评论中所说,这取决于代理将使用的对象是否也被处理
假设我们有一个“最坏情况”场景,在该场景中,代理确实需要使用将被处置的对象。
处理此问题的一个好方法类似于进程
对象的方法:WaitForExit()
。此方法将简单地循环,直到看到代理完成工作(在代理运行之前和之后设置working
bool),然后返回。现在,您可以在使用该类的代码中使用类似的内容:
// Time to shut down
myDisposable.WaitForFinish();
myDisposable.Dispose();
因此,我们基本上是在处理委托之前确保委托已完成,停止任何类型的ObjectDisposedException
这有多种方法,正如Alex在评论中所说,这取决于委托将使用的对象是否也被处理
假设我们有一个“最坏情况”场景,在该场景中,代理确实需要使用将被处置的对象。
处理此问题的一个好方法类似于进程
对象的方法:WaitForExit()
。此方法将简单地循环,直到看到代理完成工作(在代理运行之前和之后设置working
bool),然后返回。现在,您可以在使用该类的代码中使用类似的内容:
// Time to shut down
myDisposable.WaitForFinish();
myDisposable.Dispose();
因此,我们基本上是在处理委托之前确保委托完成,停止任何类型的ObjectDisposedException
如果在处理过程中需要停止计时器,并且计时器委托中的工作可能仍在进行中,这依赖于共享资源,同时被处理,则需要协调“关机”过程。下面的代码片段显示了执行此操作的示例:
public class PeriodicTimerTask : IDisposable
{
private readonly System.Timers.Timer _timer;
private CancellationTokenSource _tokenSource;
private readonly ManualResetEventSlim _callbackComplete;
private readonly Action<CancellationToken> _userTask;
public PeriodicTimerTask(TimeSpan interval, Action<CancellationToken> userTask)
{
_tokenSource = new CancellationTokenSource();
_userTask = userTask;
_callbackComplete = new ManualResetEventSlim(true);
_timer = new System.Timers.Timer(interval.TotalMilliseconds);
}
public void Start()
{
if (_tokenSource != null)
{
_timer.Elapsed += (sender, e) => Tick();
_timer.AutoReset = true;
_timer.Start();
}
}
public void Stop()
{
var tokenSource = Interlocked.Exchange(ref _tokenSource, null);
if (tokenSource != null)
{
_timer.Stop();
tokenSource.Cancel();
_callbackComplete.Wait();
_timer.Dispose();
_callbackComplete.Dispose();
tokenSource.Dispose();
}
}
public void Dispose()
{
Stop();
GC.SuppressFinalize(this);
}
private void Tick()
{
var tokenSource = _tokenSource;
if (tokenSource != null && !tokenSource.IsCancellationRequested)
{
try
{
_callbackComplete.Wait(tokenSource.Token); // prevent multiple ticks.
_callbackComplete.Reset();
try
{
tokenSource = _tokenSource;
if (tokenSource != null && !tokenSource.IsCancellationRequested)
_userTask(tokenSource.Token);
}
finally
{
_callbackComplete.Set();
}
}
catch (OperationCanceledException) { }
}
}
}
公共类PeriodicTimerTask:IDisposable
{
专用只读系统.Timers.Timer\u Timer;
私有取消令牌源\u令牌源;
专用只读手册ResetEventSlim\u callbackComplete;
私有只读操作_userTask;
公共周期ICTimerTask(时间跨度间隔,操作用户任务)
{
_tokenSource=新的CancellationTokenSource();
_userTask=userTask;
_callbackComplete=新的ManualResetEventSlim(真);
_计时器=新系统.计时器.计时器(间隔.总毫秒);
}
公开作废开始()
{
if(_tokenSource!=null)
{
_timer.appead+=(发送方,e)=>勾选();
_timer.AutoReset=true;
_timer.Start();
}
}
公共停车场()
{
var tokenSource=Interlocked.Exchange(ref\u tokenSource,null);
if(令牌源!=null)
{
_timer.Stop();
tokenSource.Cancel();
_callbackComplete.Wait();
_timer.Dispose();
_callbackComplete.Dispose();
tokenSource.Dispose();
}
}
公共空间处置()
{
停止();
总干事(本);
}
私人空白勾号()
{
var tokenSource=\u tokenSource;
if(tokenSource!=null&&!tokenSource.IsCancellationRequested)
{
尝试
{
_callbackComplete.Wait(tokenSource.Token);//防止多个记号。
_callbackComplete.Reset();
尝试
{
令牌源=_令牌源;
if(tokenSource!=null&&!tokenSource.IsCancellationRequested)
_userTask(tokenSource.Token);
}
最后
{
_callbackComplete.Set();
}
}
捕获(操作取消异常){}
}
}
}
用法示例:
public static void Main(params string[] args)
{
var periodic = new PeriodicTimerTask(TimeSpan.FromSeconds(1), cancel => {
int n = 0;
Console.Write("Tick ...");
while (!cancel.IsCancellationRequested && n < 100000)
{
n++;
}
Console.WriteLine(" completed.");
});
periodic.Start();
Console.WriteLine("Press <ENTER> to stop");
Console.ReadLine();
Console.WriteLine("Stopping");
periodic.Dispose();
Console.WriteLine("Stopped");
}
publicstaticvoidmain(参数字符串[]args)
{
var periodic=new PeriodicTimerTask(TimeSpan.FromSeconds(1),cancel=>{
int n=0;
控制台。写(“勾选…”);
而(!cancel.IsCancellationRequested&&n<100000)
{
n++;
}
Console.WriteLine(“已完成”);
});
periodic.Start();
控制台。写入线(“按下停止”);
Console.ReadLine();
控制台。写入线(“停止”);
periodic.Dispose();
控制台。写入线(“停止”);
}
输出如下:
Press <ENTER> to stop
Tick ... completed.
Tick ... completed.
Tick ... completed.
Tick ... completed.
Tick ... completed.
Stopping
Stopped
按下可停止
勾选…完成。
勾选…完成。
勾选…完成。
勾选…完成。
勾选…完成。
停止
停止
如果在处理过程中需要停止计时器,并且计时器委托中的工作可能仍在进行中(该委托依赖于共享资源),同时被处理,则需要协调“关闭”过程。下面的代码片段显示了这样做的示例:
public class PeriodicTimerTask : IDisposable
{
private readonly System.Timers.Timer _timer;
private CancellationTokenSource _tokenSource;
private readonly ManualResetEventSlim _callbackComplete;
private readonly Action<CancellationToken> _userTask;
public PeriodicTimerTask(TimeSpan interval, Action<CancellationToken> userTask)
{
_tokenSource = new CancellationTokenSource();
_userTask = userTask;
_callbackComplete = new ManualResetEventSlim(true);
_timer = new System.Timers.Timer(interval.TotalMilliseconds);
}
public void Start()
{
if (_tokenSource != null)
{
_timer.Elapsed += (sender, e) => Tick();
_timer.AutoReset = true;
_timer.Start();
}
}
public void Stop()
{
var tokenSource = Interlocked.Exchange(ref _tokenSource, null);
if (tokenSource != null)
{
_timer.Stop();
tokenSource.Cancel();
_callbackComplete.Wait();
_timer.Dispose();
_callbackComplete.Dispose();
tokenSource.Dispose();
}
}
public void Dispose()
{
Stop();
GC.SuppressFinalize(this);
}
private void Tick()
{
var tokenSource = _tokenSource;
if (tokenSource != null && !tokenSource.IsCancellationRequested)
{
try
{
_callbackComplete.Wait(tokenSource.Token); // prevent multiple ticks.
_callbackComplete.Reset();
try
{
tokenSource = _tokenSource;
if (tokenSource != null && !tokenSource.IsCancellationRequested)
_userTask(tokenSource.Token);
}
finally
{
_callbackComplete.Set();
}
}
catch (OperationCanceledException) { }
}
}
}
公共类PeriodicTimerTask:IDisposable
{
专用只读系统.Timers.Timer\u Timer;
私有取消令牌源\u令牌源;
专用只读手册ResetEventSlim\u callbackComplete;
私有只读操作_userTask;
公共周期ICTimerTask(时间跨度间隔,操作用户任务)
{
_tokenSource=新的CancellationTokenSource();
_userTask=userTask;
_callbackComplete=新的ManualResetEventSlim(真);
_钛