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);
             }
         }
     }
 }
예제 #2
0
        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);
                }
            }
        }
예제 #3
0
        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);
                }
            };
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
 public void Enqueue(T item)
 {
     _wrapped.Add(item);
 }
예제 #8
0
        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));
            };
        }
예제 #9
0
        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);
        }
예제 #10
0
        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));
            };
        }
예제 #11
0
 public void Add(T item)
 {
     _wrapped.Add(item);
 }
예제 #12
0
        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));
        }
예제 #13
0
 private void AddWaiter(TaskCompletionSource <bool> source)
 {
     _asyncWaiters.Add(source);
 }