简体   繁体   中英

How does a Timer Elapsed event compete with High Priority threads?

I have a System.Timers.Timer object that I want to use, but I don't want the processing tied to the Timer to interfere with normal to high priority threads. In other words, I'd like to say that I want to process X every 5 seconds as long as nothing else is running .

How could I ensure that my Timer operations are running in a low-priority manner?

The nice thing about System.Timers.Timer is that you can assign a synchronzing object via the SynchronizingObject property and then exploit it to run the Elapsed event a thread whose priority can be controlled.

Just assign an instance of the ElapsedEventReceiver to the SynchronizingObject property of your timer.

Disclaimer: I whipped this up pretty fast so you will need to add your own finishing touches to make it more robust.

public class ElapsedEventReceiver : ISynchronizeInvoke
{
    private Thread m_Thread;
    private BlockingCollection<Message> m_Queue = new BlockingCollection<Message>();

    public ElapsedEventReceiver()
    {
        m_Thread = new Thread(Run);
        m_Thread.Priority = ThreadPriority.BelowNormal;
        m_Thread.IsBackground = true;
        m_Thread.Start();
    }

    private void Run()
    {
        while (true)
        {
            Message message = m_Queue.Take();
            message.Return = message.Method.DynamicInvoke(message.Args);
            message.Finished.Set();
        }
    }

    public IAsyncResult BeginInvoke(Delegate method, object[] args)
    {
        Message message = new Message();
        message.Method = method;
        message.Args = args;
        m_Queue.Add(message);
        return message;
    }

    public object EndInvoke(IAsyncResult result)
    {
        Message message = result as Message;
        if (message != null)
        {
            message.Finished.WaitOne();
            return message.Return;
        }
        throw new ArgumentException("result");
    }

    public object Invoke(Delegate method, object[] args)
    {
        Message message = new Message();
        message.Method = method;
        message.Args = args;
        m_Queue.Add(message);
        message.Finished.WaitOne();
        return message.Return;
    }

    public bool InvokeRequired
    {
        get { return Thread.CurrentThread != m_Thread; }
    }

    private class Message : IAsyncResult
    {
        public Delegate Method;
        public object[] Args;
        public object Return;
        public object State;
        public ManualResetEvent Finished = new ManualResetEvent(false);

        public object AsyncState
        {
            get { return State; }
        }

        public WaitHandle AsyncWaitHandle
        {
            get { return Finished; }
        }

        public bool CompletedSynchronously
        {
            get { return false; }
        }

        public bool IsCompleted
        {
            get { return Finished.WaitOne(0); }
        }
    }
}

Probably the easiest way would be to have a "busy" flag (or count), and ignore the timer ticks as long as it's non-zero.

PS Changing thread priorities is not recommended. It's hardly ever necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM