Example #1
0
            /// <summary>
            /// Creates a new <see cref="Delegator"/> instance which invokes the
            /// given delegates when <see cref="SetUp"/> and <see cref="TearDown"/>
            /// are called.
            /// </summary>
            /// <param name="setup"></param>
            /// The delegate to invoke when <see cref="SetUp"/> is called.
            /// <param name="teardown">
            /// The delegate to invoke when <see cref="TearDown"/> is called.
            /// </param>
            public Delegator(EventQueue dispatcher, Collection <V> collection,
                             SetUpDelegate setup, TearDownDelegate teardown)
                : base(dispatcher, collection)
            {
                this.s = setup;

                this.t = (teardown != null) ? teardown : new TearDownDelegate(base.TearDown);
            }
Example #2
0
        /// <summary>
        /// This creates a new timer that runs on a new thread (not threadpool thread).  All three of the delegates passed in will be executed
        /// from that newly created threads
        /// </summary>
        /// <param name="prep">
        /// This gives the caller a chance to set up objects for the tick to use (those objects won't need to be threadsafe, because they will be created and
        /// used only on the background thread for this instance of timer
        /// </param>
        /// <param name="tick">
        /// This gets fired every internal (arg is the object returned from prep
        /// NOTE: If the code in this tick takes longer than interval, subsequent ticks will just get eaten, so no danger
        /// </param>
        /// <param name="tearDown">
        /// This gets called when this timer is disposed.  Gives the user a chance to dispose anything they created in prep
        /// </param>
        public TimerCreateThread(PrepDelegate prep = null, TickDelegate tick = null, TearDownDelegate tearDown = null, params object[] prepArgs)
        {
            //TODO: figure out how to use ParameterizedThreadStart instead of using member variables
            _prep     = prep;
            _prepArgs = prepArgs;
            _tick     = tick;
            _tearDown = tearDown;

            Thread workerThread = new Thread(WorkerMethod);

            workerThread.IsBackground = true;
            workerThread.Start();
        }
Example #3
0
        private void WorkerMethod()
        {
            // Doing this so TaskScheduler.FromCurrentSynchronizationContext() will work
            SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

            // Since _tearDown gets called after dispose, there's a slight chance that the underlying object could get garbage collected, so store local copies of these
            // two delegates up front
            TickDelegate     tick     = _tick;
            TearDownDelegate tearDown = _tearDown;

            // Let the client create an object from this thread
            T prepResults = default(T);

            if (_prep != null)
            {
                prepResults = _prep(_prepArgs);
            }

            #region Set up the timer

            DateTime lastTick = DateTime.UtcNow;

            ManualResetEvent tickEvent = new ManualResetEvent(false);

            System.Timers.Timer timer = new System.Timers.Timer();
            //timer.SynchronizingObject     //NOTE: I tried to implement ISynchonizeInvoke, but that approach was a mess.  I think this approach of creating a thead for the user is way cleaner
            timer.Interval  = this.Interval;
            timer.Elapsed  += delegate { tickEvent.Set(); };
            timer.AutoReset = false;
            if (_isTimerRunning)
            {
                timer.Start();
            }

            #endregion

            WaitHandle[] handles = new WaitHandle[] { _disposeEvent, _timerSettingsChanged, tickEvent };

            while (true)
            {
                // Hang this thread until something happens
                int handleIndex = WaitHandle.WaitAny(handles);

                if (handleIndex == 0)       // I would prefer a switch statement, but there is no Exit While statement
                {
                    // Dispose was called, this thread needs to finish
                    //_disposeEvent.Reset();        // just leave this one tripped so that
                    break;
                }
                else if (handleIndex == 1)
                {
                    #region Timer settings changed

                    _timerSettingsChanged.Reset();

                    // Settings for the timer have changed
                    timer.Interval = this.Interval;

                    if (_isTimerRunning)
                    {
                        timer.Start();      // it appears to be safe to call this even when started
                    }
                    else
                    {
                        timer.Stop();       // and to call this again when stopped
                    }

                    #endregion
                }
                else if (handleIndex == 2)
                {
                    #region Timer ticked

                    DateTime currentTick = DateTime.UtcNow;
                    double   elapsed     = (currentTick - lastTick).TotalMilliseconds;
                    lastTick = currentTick;

                    tickEvent.Reset();

                    if (_isTimerRunning)
                    {
                        timer.Start();

                        if (tick != null)       // putting this inside the _isTimerRunning, because they may have wanted the timer stopped between ticks, so in that case, just ignore this tick event
                        {
                            tick(prepResults, elapsed);
                        }
                    }

                    #endregion
                }
                else
                {
                    throw new ApplicationException("Unknown wait handle: " + handleIndex.ToString());
                }
            }

            timer.Stop();
            timer.Dispose();

            if (tearDown != null)
            {
                tearDown(prepResults);
            }
        }