如何立即停止计时器以及如何禁用线程池排队?

时间:2018-03-19 13:52:38

标签: c#

如何立即停止计时器。当我使用下面的代码在计时器处理程序设置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);
        }
    }
}

}

1 个答案:

答案 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();
        }
    }
}