如何立即停止计时器。当我使用下面的代码在计时器处理程序设置Auto = false中运行lenghty作业时,不立即停止计时器。我认为计时器线程仍然在运行,在完成工作后它将终止。当Auto设置为false时,如何使代码清理计时器线程,停止在其中运行的耗时作业?
其次,当IntervalSeconds过去且前一个线程仍在运行完成一个lenghty任务时,我不希望线程在线程池中排队。代码是否以正确的方式执行此操作?
class AutoObject : IDisposable
{
private bool m_bAuto;
private System.Timers.Timer m_Timer = null;
private int m_nIntervalSeconds = 60;
private readonly object m_PadLock = new object();
public event EventHandler AutoTimeElapsed;
public bool StartInstantly { get; private set; }
public virtual bool Auto
{
get { return m_bAuto; }
set
{
if (m_bAuto != value)
{
DisposeTimer();
if (value)
{
m_Timer = CreateTimer(IntervalSeconds, true); // Creates a running timer.
if (StartInstantly)
OnAutoTimeElapsed(EventArgs.Empty);
}
m_bAuto = value;
}
}
}
public virtual int IntervalSeconds
{
get { return m_nIntervalSeconds; }
set
{
if (m_nIntervalSeconds != value)
{
if (value <= 0)
throw new ArgumentException("IntervalSeconds property must be greater than zero.");
if (m_bAuto)
{
DisposeTimer();
m_Timer = CreateTimer(value, true); // Creates a running timer.
if (StartInstantly)
OnAutoTimeElapsed(EventArgs.Empty);
}
m_nIntervalSeconds = value;
}
}
}
public AutoObject(bool bAuto, bool bStartInstantly)
{
StartInstantly = bStartInstantly;
Auto = bAuto;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void OnAutoTimeElapsed(EventArgs e)
{
AutoTimeElapsed?.Invoke(this, e);
}
protected virtual void Dispose(bool bDisposing)
{
if (bDisposing)
DisposeTimer();
}
private System.Timers.Timer CreateTimer(int nIntervalSeconds, bool bEnabled)
{
System.Timers.Timer Timer = new System.Timers.Timer();
Timer.Interval = nIntervalSeconds * 1000;
Timer.Enabled = bEnabled;
Timer.Elapsed += new ElapsedEventHandler(OnTimerElapsed);
return Timer;
}
private void DisposeTimer()
{
if (m_Timer != null)
{
if (m_Timer.Enabled)
m_Timer.Enabled = false;
m_Timer.Dispose(); // Thread is still running ??
m_Timer = null;
}
}
// If the time needed to process a task is greater than the timer
// interval I want to completely throw away the "extra" execution,
// without queuing the thread. Is this the right way to do it ??
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
bool bLocked = false;
try
{
bLocked = Monitor.TryEnter(m_PadLock);
if (bLocked)
OnAutoTimeElapsed(e);
}
finally
{
if (bLocked)
Monitor.Exit(m_PadLock);
}
}
}
}
答案 0 :(得分:0)
如果是我,我根本不会使用计时器,而是在一个单独的线程上有一个循环,在处理结束时等待。
在循环中,您可以检查是否已经请求停止并尽快退出。Monitor.Pulse可用于立即退出任何等待的线程。
这将完成任务,然后在再次启动之前等待间隔,这样它就不能再运行一次。
例如:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
private bool _stopRequested = false;
private TimeSpan _interval = TimeSpan.FromMinutes(1);
private readonly object _monitorLock = new object();
private Thread _thread = null;
public Form1()
{
InitializeComponent();
ThreadStart threadStart = new ThreadStart(this.DoWork);
_thread = new Thread(threadStart);
}
void DoWork()
{
while (!_stopRequested)
{
lock (_monitorLock)
{
//Do Processing, whilst Checking for whether stop requested has been set. If it has return out.
for (int i = 0; i < 100; i++)
{
if (_stopRequested) return;
Debug.WriteLine($"Processing: {i}");
Thread.Sleep(TimeSpan.FromSeconds(1));
}
Monitor.Wait(_monitorLock, _interval);
}
}
}
public void RequestStart()
{
_stopRequested = false;
_thread.Start();
}
public void RequestStop()
{
_stopRequested = true;
//Lock the monitor object
lock (_monitorLock)
{
//Pulse the monitor lock to release it
Monitor.Pulse(_monitorLock);
}
}
private void btnStart_Click(object sender, EventArgs e)
{
this.RequestStart();
}
private void btnStop_Click(object sender, EventArgs e)
{
this.RequestStop();
}
}
}