private void Awake() { // Call this to notify that there is room in the semaphore // Allow sync waiters to proceed _event.Set(); while (Thread.VolatileRead(ref _count) < _maxCount) { TaskCompletionSource <bool> waiter; if (_asyncWaiters.TryTake(out waiter)) { if (waiter.Task.IsCompleted) { // Skip - either canceled or timed out continue; } if (TryEnter()) { waiter.SetResult(true); } else { _asyncWaiters.Add(waiter); } } } }
private void Awake(int releaseCount) { // Call this to notify that there is room in the semaphore // Allow sync waiters to proceed _event.Set(); TaskCompletionSource <bool> waiter; while (releaseCount > 0 && _asyncWaiters.TryTake(out waiter)) { releaseCount--; if (waiter.Task.IsCompleted) { // Skip - either canceled or timed out continue; } if (TryEnter()) { waiter.SetResult(true); } else { _asyncWaiters.Add(waiter); } } }
public Progressor(Progressor <T> wrapped) { if (wrapped == null) { throw new ArgumentNullException("wrapped"); } var control = 0; Predicate <T> newFilter = item => Thread.VolatileRead(ref control) == 0; var buffer = new SafeQueue <T>(); wrapped.SubscribeAction ( item => { if (newFilter(item)) { buffer.Add(item); } } ); _proxy = new ProxyObservable <T>(); _tryTake = (out T value) => { Interlocked.Increment(ref control); try { if (buffer.TryTake(out value) || wrapped.TryTake(out value)) { _proxy.OnNext(value); return(true); } else { _done = wrapped._done; return(false); } } finally { Interlocked.Decrement(ref control); } }; }
private bool MoveNext() { TSource item; if (_enumerator == null) { return(false); } lock (_enumerator) { if (!_enumerator.MoveNext()) { _enumerator.Dispose(); _cancellationTokenSource.Cancel(); _enumerator = null; return(false); } item = _enumerator.Current; } var key = _keySelector(item); var element = _resultSelector(item); if (_proxies.TryGetOrAdd(key, _ => new ProxyObservable <TElement>(), out var proxy)) { var progressor = Progressor <TElement> .CreateFromIObservable ( proxy, Advance, _cancellationTokenSource.Token ); var items = ProgressiveCollection <TElement> .Create <SafeCollection <TElement> > ( progressor, EqualityComparer <TElement> .Default ); var result = new Grouping <TKey, TElement>(key, items); _results.Add(result); } proxy.OnNext(element); return(true); }
private static IPromise <T> AddExecution <T>(Func <T> action, SafeQueue <Action> queue) { var promised = new PromiseNeedle <T>(false); var result = new ReadOnlyPromiseNeedle <T>(promised, false); queue.Add ( () => { try { promised.Value = action.Invoke(); } catch (Exception exception) { promised.SetError(exception); } } ); return(result); }
private static IPromise AddExecution(Action action, SafeQueue <Action> queue) { var promised = new Promise(false); var result = new ReadOnlyPromise(promised, false); queue.Add ( () => { try { action.Invoke(); promised.SetCompleted(); } catch (Exception exception) { promised.SetError(exception); } } ); return(result); }
public void Enqueue(T item) { _wrapped.Add(item); }
public Progressor(IEnumerable <T> preface, Progressor <T> wrapped) { if (wrapped == null) { throw new ArgumentNullException("wrapped"); } if (preface == null) { throw new ArgumentNullException("preface"); } var enumerator = preface.GetEnumerator(); if (enumerator == null) { throw new ArgumentException("preface.GetEnumerator()"); } var control = 0; var guard = 0; Predicate <T> newFilter = item => Thread.VolatileRead(ref control) == 0; var buffer = new SafeQueue <T>(); wrapped.SubscribeAction ( item => { if (newFilter(item)) { buffer.Add(item); } } ); _proxy = new ProxyObservable <T>(); TryTake <T> tryTakeReplacement = (out T value) => { Interlocked.Increment(ref control); try { if (buffer.TryTake(out value) || wrapped.TryTake(out value)) { _proxy.OnNext(value); return(true); } else { _done = wrapped._done; return(false); } } finally { Interlocked.Decrement(ref control); } }; _tryTake = (out T value) => { value = default(T); if (Thread.VolatileRead(ref guard) == 0) { bool result; // We need a lock, there is no way around it. IEnumerator is just awful. Use another overload if possible. lock (enumerator) { result = enumerator.MoveNext(); if (result) { value = enumerator.Current; } } if (result) { _proxy.OnNext(value); return(true); } enumerator.Dispose(); Interlocked.CompareExchange(ref guard, 1, 0); } if (Interlocked.CompareExchange(ref guard, 2, 1) == 1) { _tryTake = tryTakeReplacement; Thread.VolatileWrite(ref guard, 3); } else { ThreadingHelper.SpinWaitUntil(ref guard, 3); } var tryTake = _tryTake; return(tryTake(out value)); }; }
public static Progressor <T> CreatedFilteredConverted <TInput>(Progressor <TInput> wrapped, Predicate <TInput> filter, Converter <TInput, T> converter) { if (wrapped == null) { throw new ArgumentNullException("wrapped"); } if (filter == null) { throw new ArgumentNullException("filter"); } if (converter == null) { throw new ArgumentNullException("converter"); } var control = 0; Predicate <TInput> newFilter = item => Thread.VolatileRead(ref control) == 0 && filter(item); var buffer = new SafeQueue <T>(); var proxy = new ProxyObservable <T>(); var result = new Progressor <T>( (out T value) => { Interlocked.Increment(ref control); try { TInput item; again: if (buffer.TryTake(out value)) { proxy.OnNext(value); return(true); } else if (wrapped.TryTake(out item)) { if (filter(item)) { value = converter(item); proxy.OnNext(value); return(true); } else { goto again; } } value = default(T); return(false); } finally { Interlocked.Decrement(ref control); } }, proxy ); wrapped.Subscribe ( new CustomObserver <TInput> ( () => result._done = true, exception => result._done = true, item => { if (newFilter(item)) { buffer.Add(converter(item)); } } ) ); return(result); }
public Progressor(T[] preface, Progressor <T> wrapped) { if (wrapped == null) { throw new ArgumentNullException("wrapped"); } if (preface == null) { throw new ArgumentNullException("preface"); } var control = 0; var guard = 0; var index = -1; Predicate <T> newFilter = item => Thread.VolatileRead(ref control) == 0; var buffer = new SafeQueue <T>(); wrapped.SubscribeAction ( item => { if (newFilter(item)) { buffer.Add(item); } } ); _proxy = new ProxyObservable <T>(); TryTake <T> tryTakeReplacement = (out T value) => { Interlocked.Increment(ref control); try { if (buffer.TryTake(out value) || wrapped.TryTake(out value)) { _proxy.OnNext(value); return(true); } else { _done = wrapped._done; return(false); } } finally { Interlocked.Decrement(ref control); } }; _tryTake = (out T value) => { if (Thread.VolatileRead(ref guard) == 0) { var currentIndex = Interlocked.Increment(ref index); if (currentIndex < preface.Length) { value = preface[currentIndex]; _proxy.OnNext(value); return(true); } Interlocked.CompareExchange(ref guard, 1, 0); } if (Interlocked.CompareExchange(ref guard, 2, 1) == 1) { _tryTake = tryTakeReplacement; Thread.VolatileWrite(ref guard, 3); } else { ThreadingHelper.SpinWaitUntil(ref guard, 3); } var tryTake = _tryTake; return(tryTake(out value)); }; }
public void Add(T item) { _wrapped.Add(item); }
public static Progressor <T> CreateFromIObservable(IObservable <T> observable, Action exhaustedCallback = null, CancellationToken token = default) { if (observable == null) { throw new ArgumentNullException(nameof(observable)); } if (exhaustedCallback == null) { exhaustedCallback = ActionHelper.GetNoopAction(); } var buffer = new SafeQueue <T>(); var semaphore = new SemaphoreSlim(0); var source = new CancellationTokenSource(); var subscription = observable.Subscribe ( new CustomObserver <T>( onCompleted: source.Cancel, onError: exception => source.Cancel(), onNext: OnNext ) ); var proxy = new ProxyObservable <T>(); var tryTake = new TryTake <T>[] { null }; tryTake[0] = TakeInitial; void OnNext(T item) { buffer.Add(item); semaphore.Release(); } bool TakeInitial(out T value) { if (source.IsCancellationRequested || token.IsCancellationRequested) { if (Interlocked.CompareExchange(ref tryTake[0], TakeReplacement, tryTake[0]) == tryTake[0]) { Interlocked.Exchange(ref subscription, null)?.Dispose(); } } else { if (exhaustedCallback != null) { var spinWait = new SpinWait(); while ( semaphore.CurrentCount == 0 && !source.IsCancellationRequested && !token.IsCancellationRequested ) { exhaustedCallback(); spinWait.SpinOnce(); } } } if (!source.IsCancellationRequested && !token.IsCancellationRequested) { try { semaphore.Wait(source.Token); } catch (OperationCanceledException exception) { GC.KeepAlive(exception); } } return(TakeReplacement(out value)); } bool TakeReplacement(out T value) { if (buffer.TryTake(out value)) { return(true); } value = default; return(false); } bool Take(out T value) { return(tryTake[0](out value)); } return(new Progressor <T>(proxy, Take)); }
private void AddWaiter(TaskCompletionSource <bool> source) { _asyncWaiters.Add(source); }