2

After reading SO extensively, I understand that Thread.Sleep is a bad idea. Instead, the general consensus is that server-side tasks should use a Timer, a threadpool, or maybe use a Join().

One article mentions difficulties in disposing the timer.

Another article mentions using waitOne

Question

What is the right approach to use when launching a long running task that will repeat every 30 seconds, 1 minute, or 5 minutes? The constraint is that IF the previous run of that task is longer than the interval (32 seconds, or 7 minutes) then I want the option to either kill that previous instance, or not execute a new instance.

A potential gotcha is that I intend to use impersonation on these threads using either WindowsImpersionationContext, P/InvokeLogonUserEX, or DCOMShim as needed.

I'm not sure what approach to take, and why.

Possible Answer 1

This example appears to be straightforward, with minimal code clutter

    // initially set to a "non-signaled" state, ie will block
    // if inspected
   private readonly AutoResetEvent _isStopping = new AutoResetEvent(false);
    /// <summary>
    /// from...
    /// https://stackoverflow.com/questions/2822441/system-timers-timer-threading-timer-vs-thread-with-whileloop-thread-sleep-for-p/2822506#2822506
    /// </summary>
    public void SampleDelay1()
    {
        TimeSpan waitInterval = TimeSpan.FromMilliseconds(1000);

        // will block for 'waitInterval', unless another thread,
        // say a thread requesting termination, wakes you up. if
        // no one signals you, WaitOne returns false, otherwise
        // if someone signals WaitOne returns true
        for (; !_isStopping.WaitOne(waitInterval); )
        {
            // do your thang!
        }
    }

Possible Answer 2

This example offers similar functionality, but uses anonymous types that may not be permitted in companies that don't allow for that in their coding standard.

 /// <summary>
    /// Disposable Timer instance from 
    /// https://stackoverflow.com/questions/391621/compare-using-thread-sleep-and-timer-for-delayed-execution
    /// </summary>
    class TimerStackOverFlow
    {
   // Created by Roy Feintuch 2009
        // Basically we wrap a timer object in order to send itself as a context in order
        // to dispose it after the cb invocation finished. This solves the problem of timer 
        // being GCed because going out of context
        public static void DoOneTime(ThreadStart cb, TimeSpan dueTime)
        {
            var td = new TimerDisposer();
            // Is the next object System.Timers, or System.Threading
            var timer = new Timer(myTdToKill =>
            {
                try
                {
                    cb();
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(string.Format("[DoOneTime] Error occured while invoking delegate. {0}", ex), "[OneTimer]");
                }
                finally
                {
                    ((TimerDisposer)myTdToKill).InternalTimer.Dispose();
                }
            },
                        td, dueTime, TimeSpan.FromMilliseconds(-1));

            td.InternalTimer = timer;
        }
    }

    class TimerDisposer
    {
        public Timer InternalTimer { get; set; }
    }
Community
  • 1
  • 1
makerofthings7
  • 60,103
  • 53
  • 215
  • 448

1 Answers1

0

I've used your first approach many times, and it works well.

The second solution appears to be a generic encapsulation of a time-based trigger for a one-time event. If you're looking at recurring events, then this approach seems unnecessarily complicated to me with no obvious benefit gained from the added complexity.