コード例 #1
0
        public void Subscribe(ISignalObserver <T> observer)
        {
            var ccd = new CacheConsumerDisposable(observer, this, head);

            observer.OnSubscribe(ccd);
            Add(ccd);
            if (ccd.IsDisposed())
            {
                Remove(ccd);
                return;
            }
            if (Volatile.Read(ref once) == 0 && Interlocked.CompareExchange(ref once, 1, 0) == 0)
            {
                cancel?.Invoke(this);

                source.Subscribe(this);
            }
            Drain(ccd);
        }
コード例 #2
0
        void Drain(CacheConsumerDisposable ccd)
        {
            if (Interlocked.Increment(ref ccd.wip) != 1)
            {
                return;
            }

            var missed     = 1;
            var downstream = ccd.downstream;

            for (; ;)
            {
                var i = ccd.index;
                var n = ccd.node;
                var o = ccd.offset;

                if (n != null)
                {
                    var a   = n.items;
                    var cap = a.Length;

                    for (; ;)
                    {
                        if (ccd.IsDisposed())
                        {
                            n = null;
                            break;
                        }
                        var ex = Volatile.Read(ref terminated);
                        var s  = Volatile.Read(ref size);

                        bool empty = i == s;

                        if (ex != null && empty)
                        {
                            if (ex == ExceptionHelper.TERMINATED)
                            {
                                downstream.OnCompleted();
                            }
                            else
                            {
                                downstream.OnError(ex);
                            }

                            n = null;
                            break;
                        }

                        if (empty)
                        {
                            break;
                        }

                        if (o == cap)
                        {
                            var b = n.next;
                            n = b;
                            a = b.items;
                            o = 0;
                        }

                        var v = a[o];

                        downstream.OnNext(v);

                        i++;
                        o++;
                    }

                    ccd.index  = i;
                    ccd.node   = n;
                    ccd.offset = o;
                }

                missed = Interlocked.Add(ref ccd.wip, -missed);
                if (missed == 0)
                {
                    break;
                }
            }
        }