public void MultipleAssignment() { var d = new MultipleAssignmentDisposable(); d.IsDisposed.IsFalse(); var id1 = new IdDisp(1); var id2 = new IdDisp(2); var id3 = new IdDisp(3); // dispose first d.Dispose(); d.IsDisposed.IsTrue(); d.Disposable = id1; id1.IsDisposed.IsTrue(); d.Disposable = id2; id2.IsDisposed.IsTrue(); d.Disposable = id3; id3.IsDisposed.IsTrue(); // normal flow d = new MultipleAssignmentDisposable(); id1 = new IdDisp(1); id2 = new IdDisp(2); id3 = new IdDisp(3); d.Disposable = id1; id1.IsDisposed.IsFalse(); d.Dispose(); id1.IsDisposed.IsTrue(); d.Disposable = id2; id2.IsDisposed.IsTrue(); d.Disposable = id3; id3.IsDisposed.IsTrue(); // exception flow d = new MultipleAssignmentDisposable(); id1 = new IdDisp(1); id2 = new IdDisp(2); id3 = new IdDisp(3); d.Disposable = id1; d.Disposable = id2; d.Disposable = id3; d.Dispose(); id1.IsDisposed.IsFalse(); id2.IsDisposed.IsFalse(); id3.IsDisposed.IsTrue(); // null d = new MultipleAssignmentDisposable(); id1 = new IdDisp(1); d.Disposable = null; d.Dispose(); d.Disposable = null; }
private IDisposable ScheduleSlow <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action) { var d = new MultipleAssignmentDisposable(); var timer = new System.Windows.Threading.DispatcherTimer(Priority, Dispatcher); timer.Tick += (s, e) => { var t = Interlocked.Exchange(ref timer, null); if (t != null) { try { d.Disposable = action(this, state); } finally { t.Stop(); action = null; } } }; timer.Interval = dueTime; timer.Start(); d.Disposable = Disposable.Create(() => { var t = Interlocked.Exchange(ref timer, null); if (t != null) { t.Stop(); action = (_, __) => Disposable.Empty; } }); return(d); }
/// <summary> /// Schedules an action to be executed after dueTime on the message loop associated with the control, using a Windows Forms Timer object. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Relative time after which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception> public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } var dt = Scheduler.Normalize(dueTime); if (dt.Ticks == 0) { return(Schedule(state, action)); } var createTimer = new Func <IScheduler, TState, IDisposable>((scheduler1, state1) => { var d = new MultipleAssignmentDisposable(); var timer = new System.Windows.Forms.Timer(); timer.Tick += (s, e) => { var t = Interlocked.Exchange(ref timer, null); if (t != null) { try { if (!_control.IsDisposed && !d.IsDisposed) { d.Disposable = action(scheduler1, state1); } } finally { t.Stop(); action = static (s, t) => Disposable.Empty; } }
public static IObservable <T> ObserveLatestOn <T>(this IObservable <T> source, IScheduler scheduler) => Observable.Create <T>(observer => { Notification <T> outsideNotification; var gate = new object(); var active = false; var cancelable = new MultipleAssignmentDisposable(); var disposable = source.Materialize().Subscribe(thisNotification => { bool wasNotAlreadyActive; lock (gate){ wasNotAlreadyActive = !active; active = true; outsideNotification = thisNotification; } if (wasNotAlreadyActive) { cancelable.Disposable = scheduler.Schedule(self => { Notification <T> localNotification; lock (gate){ localNotification = outsideNotification; outsideNotification = null; } localNotification.Accept(observer); bool hasPendingNotification; lock (gate){ hasPendingNotification = active = outsideNotification != null; } if (hasPendingNotification) { self(); } }); } }); return(new CompositeDisposable(disposable, cancelable)); });
/// <summary> /// Schedules an action to be executed after dueTime. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Relative time after which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception> public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException("action"); } var dt = Scheduler.Normalize(dueTime); if (dt.Ticks == 0) { return(Schedule(state, action)); } #if !NO_TASK_DELAY var d = new MultipleAssignmentDisposable(); var ct = new CancellationDisposable(); d.Disposable = ct; #if USE_TASKEX TaskEx.Delay(dueTime, ct.Token).ContinueWith(_ => #else Task.Delay(dueTime, ct.Token).ContinueWith(_ => #endif { if (!d.IsDisposed) { d.Disposable = action(this, state); } }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, taskFactory.Scheduler); return(d); #else return(DefaultScheduler.Instance.Schedule(state, dt, (_, state1) => Schedule(state1, action))); #endif }
protected override IDisposable SubscribeCore(IObserver <T> observer, IDisposable cancel) { if (dueTimeT != null) { var d = new MultipleAssignmentDisposable(); var dt = Scheduler.Normalize(dueTimeT.Value); d.Disposable = scheduler.Schedule(dt, () => { d.Disposable = source.Subscribe(observer); }); return(d); } else { var d = new MultipleAssignmentDisposable(); d.Disposable = scheduler.Schedule(dueTimeD.Value, () => { d.Disposable = source.Subscribe(observer); }); return(d); } }
public IDisposable Schedule(Action action, TimeSpan delay) { MultipleAssignmentDisposable inner = new MultipleAssignmentDisposable(); MultipleAssignmentDisposable outer = new MultipleAssignmentDisposable(inner); if (tasks.Add(outer)) { IDisposable cancel = new ActionWeakDisposable(() => tasks.Remove(outer)); IDisposable f = Task.Delay(delay).ContinueWith(a => { if (!outer.IsDisposed()) { outer.Set(Schedule(action)); } }); inner.Set(f); return(cancel); } return(EmptyDisposable.Instance); }
public static Func <Action <TResult>, Action <Exception>, IBackgroundTask> CreateForAsync <TResult>(FSharpAsync <TResult> async) { return((onSuccess, onError) => { var disp = new MultipleAssignmentDisposable(); var backgroundTask = new AnonymousBackgroundTask(); backgroundTask.name = "upgarde firmware"; backgroundTask.state = BackgroundTaskState.InProgress; backgroundTask.disposable = Disposable.Create(() => { disp.Dispose(); backgroundTask.state = BackgroundTaskState.Canceled; }); disp.Disposable = async.Subscribe( res => { onSuccess(res); backgroundTask.state = BackgroundTaskState.Completed; }, err => { onError(err); backgroundTask.state = BackgroundTaskState.Failed; } ); return backgroundTask; }); }
public override IDisposable Schedule(IRunnable action, TimeSpan delay) { MultipleAssignmentDisposable first = new MultipleAssignmentDisposable(); MultipleAssignmentDisposable mad = new MultipleAssignmentDisposable(first); IDisposable d = Task.Delay(delay).ContinueWith(t => { IDisposable d1 = Schedule(action); mad.Set(d1); }); first.Set(d); return mad; }
/// <summary> /// Schedules an action to be executed after dueTime on the message loop associated with the control, using a Windows Forms Timer object. /// </summary> /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam> /// <param name="state">State passed to the action to be executed.</param> /// <param name="action">Action to be executed.</param> /// <param name="dueTime">Relative time after which to execute the action.</param> /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns> /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception> public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } var dt = Scheduler.Normalize(dueTime); if (dt.Ticks == 0) { return(Schedule(state, action)); } var createTimer = new Func <IScheduler, TState, IDisposable>((scheduler1, state1) => { var d = new MultipleAssignmentDisposable(); var timer = new System.Windows.Forms.Timer(); timer.Tick += (s, e) => { var t = Interlocked.Exchange(ref timer, null); if (t != null) { try { d.Disposable = action(scheduler1, state1); } finally { t.Stop(); action = null; } } }; timer.Interval = (int)dt.TotalMilliseconds; timer.Start(); d.Disposable = Disposable.Create(() => { var t = Interlocked.Exchange(ref timer, null); if (t != null) { t.Stop(); action = (_, __) => Disposable.Empty; } }); return(d); }); // // This check is critical. When creating and enabling a Timer object on another thread than // the UI thread, it won't fire. // if (_control.InvokeRequired) { return(Schedule(state, createTimer)); } else { return(createTimer(this, state)); } }
/// <summary> /// Applies a conflation algorithm to an observable stream. /// Anytime the stream OnNext twice below minimumUpdatePeriod, the second update gets delayed to respect the minimumUpdatePeriod /// If more than 2 update happen, only the last update is pushed /// Updates are pushed and rescheduled using the provided scheduler /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source">stream</param> /// <param name="minimumUpdatePeriod">minimum delay between 2 updates</param> /// <param name="scheduler">to be used to publish updates and schedule delayed updates</param> /// <returns></returns> public static IObservable <T> Conflate <T>(this IObservable <T> source, TimeSpan minimumUpdatePeriod, IScheduler scheduler) { return(Observable.Create <T>(observer => { // indicate when the last update was published var lastUpdateTime = DateTimeOffset.MinValue; // indicate if an update is currently scheduled var updateScheduled = new MultipleAssignmentDisposable(); // indicate if completion has been requested (we can't complete immediatly if an update is in flight) var completionRequested = false; var gate = new object(); var subscription = source .ObserveOn(scheduler) .Subscribe( x => { var currentUpdateTime = scheduler.Now; bool scheduleRequired; lock (gate) { scheduleRequired = currentUpdateTime - lastUpdateTime < minimumUpdatePeriod; if (scheduleRequired && updateScheduled.Disposable != null) { updateScheduled.Disposable.Dispose(); updateScheduled.Disposable = null; } } if (scheduleRequired) { updateScheduled.Disposable = scheduler.Schedule(lastUpdateTime + minimumUpdatePeriod, () => { observer.OnNext(x); lock (gate) { lastUpdateTime = scheduler.Now; updateScheduled.Disposable = null; if (completionRequested) { observer.OnCompleted(); } } }); } else { observer.OnNext(x); lock (gate) { lastUpdateTime = scheduler.Now; } } }, observer.OnError, () => { // if we have scheduled an update we need to complete once the update has been published if (updateScheduled.Disposable != null) { lock (gate) { completionRequested = true; } } else { observer.OnCompleted(); } }); return subscription; })); }
public IDisposable Subscribe( Endpoint endpoint, Action <BinaryMessage, AcknowledgeDelegate> callback, string messageType, string processingGroup, int priority) { if (string.IsNullOrEmpty(processingGroup)) { throw new ArgumentNullException(nameof(processingGroup), "should be not empty string"); } if (m_IsDisposing) { throw new ObjectDisposedException(GetType().Name); } var subscriptionHandler = new MultipleAssignmentDisposable(); Action <int> doSubscribe = null; doSubscribe = attemptNumber => { string processingGroupName = null; if (subscriptionHandler.IsDisposed) { return; } try { var group = GetProcessingGroup(processingGroup); processingGroupName = group.Name; _log.WriteInfo( nameof(ProcessingGroupManager), nameof(Subscribe), attemptNumber > 0 ? $"Resubscribing for endpoint {endpoint} within processing group '{processingGroupName}'. Attempt# {attemptNumber}" : $"Subscribing for endpoint {endpoint} within processing group '{processingGroupName}'"); var sessionName = GetSessionName(group, priority); var session = m_TransportManager.GetMessagingSession(endpoint, sessionName, Helper.CallOnlyOnce(() => { _log.WriteInfo( nameof(ProcessingGroupManager), nameof(Subscribe), $"Subscription for endpoint {endpoint} within processing group '{processingGroupName}' failure detected. Attempting subscribe again."); doSubscribe(0); })); var subscription = group.Subscribe( session, endpoint.Destination.Subscribe, (message, ack) => callback(message, CreateDeferredAcknowledge(ack)), messageType, priority); var brokenSubscription = subscriptionHandler.Disposable; subscriptionHandler.Disposable = subscription; try { if (attemptNumber > 0) { brokenSubscription.Dispose(); } } catch { } _log.WriteInfo( nameof(ProcessingGroupManager), nameof(Subscribe), $"Subscribed for endpoint {endpoint} in processingGroup '{processingGroupName}' using session {sessionName}"); } catch (InvalidSubscriptionException e) { _log.WriteErrorAsync( nameof(ProcessingGroupManager), nameof(Subscribe), $"Failed to subscribe for endpoint {endpoint} within processing group '{processingGroupName}'", e); throw; } catch (Exception e) { _log.WriteErrorAsync( nameof(ProcessingGroupManager), nameof(Subscribe), $"Failed to subscribe for endpoint {endpoint} within processing group '{processingGroupName}'. Attempt# {attemptNumber}. Will retry in {ResubscriptionTimeout}ms", e); ScheduleSubscription(doSubscribe, attemptNumber + 1); } }; doSubscribe(0); return(subscriptionHandler); }
public SubscribeOnCompletableSubscriber(ICompletableSubscriber actual, MultipleAssignmentDisposable mad) { this.actual = actual; this.mad = mad; }