/// <summary> /// Creates a metronome with the specified parameters. It uses a static factory method /// because if there is already an existing metronome with the same parameters, that /// metronome is returned, rather than creating another one - after all, the whole /// point is to avoid a large number of tick events on the executive's event list. /// </summary> /// <param name="exec">The executive that will issue the ticks.</param> /// <param name="startAt">The time at which the metronome's ticks are to start.</param> /// <param name="finishAfter">The time at which the metronome's ticks are to stop.</param> /// <param name="period">The period of the ticking.</param> /// <returns>A metronome that meets the criteria.</returns> public static Metronome_Simple CreateMetronome(IExecutive exec, DateTime startAt, DateTime finishAfter, TimeSpan period) { Metronome_Simple retval = null; foreach (Metronome_Simple ms in m_channels) { if (ms.Executive.Equals(exec) && ms.StartAt.Equals(startAt) && ms.FinishAt.Equals(finishAfter) && ms.Period.Equals(period)) { retval = ms; break; } } if (retval == null) { retval = new Metronome_Simple(exec, startAt, finishAfter, period); m_channels.Add(exec, retval); exec.ExecutiveFinished += exec_ExecutiveFinished; } return(retval); }
/// <summary> /// Adds an error to the model, and iterates over all of the error handlers, /// allowing each in turn to respond to the error. As soon as any errorHandler /// indicates that it has HANDLED the error (by returning true from 'HandleError'), /// the error is cleared, and further handlers are not called. /// </summary> /// <param name="theError">The error that is to be added to the model's error list.</param> /// <returns>True if the error was successfully added to the model, false if it was cleared by a handler.</returns> public bool AddError(IModelError theError) { foreach (IErrorHandler errorHandler in ErrorHandlers) { if (errorHandler.HandleError(theError)) { if (ErrorCleared != null) { ErrorCleared(theError); } return(false); } } if (theError.Target == null) { throw new ApplicationException("An error was added to the model with its target set to null. This is illegal."); } m_errors.Add(theError.Target, theError); if (ErrorHappened != null) { ErrorHappened(theError); } // IF WE ARE TRANSITIONING, We are not going to abort on the // addition of an error, since there may be intermediate situations // where an error is okay. If a 'fail on the first sign of an error' // behavior is desired, then the developer can hook the // 'ErrorHappened' event. Instead, we will have the model register a // handler as the last thing done on attempting a transition, to // check that we are error-free. But, IF WE ARE NOT TRANSITIONING, // then anything that causes an error will abort the model, and move // it back to the 'Idle' state. if (!StateMachine.IsTransitioning) { if (s_diagnostics) { _Debug.WriteLine("Model.Abort() requested as a result of the addition of an error : " + theError); } if (!StateMachine.State.Equals(GetAbortEnum())) { StateMachine.DoTransition(GetAbortEnum()); } } return(true); }
private ITuple BlockingRead(object key) { lock ( m_ts ) { while (true) { ITuple tuple = NonBlockingRead(key); if (tuple != null) { return(tuple); } #region Wait 'til next post against this key. IDetachableEventController idec = m_exec.CurrentEventController; m_waitersToRead.Add(key, idec); idec.Suspend(); #endregion } } }
public void Post(ITuple tuple) { m_ts.Add(tuple.Key, tuple); tuple.OnPosted(this); if (TuplePosted != null) { TuplePosted(this, tuple); } IList wtr = m_waitersToRead[tuple.Key]; IList wtt = m_waitersToTake[tuple.Key]; m_waitersToRead.Clear(tuple.Key); m_waitersToTake.Clear(tuple.Key); foreach (IDetachableEventController idec in wtr) { idec.Resume(double.MaxValue); } foreach (IDetachableEventController idec in wtt) { idec.Resume(double.MaxValue - double.Epsilon); } }