/// <summary>
        /// Subscribes the observer to this subject and
        /// relays the live items or replays the terminal
        /// event to it.
        /// </summary>
        /// <param name="observer">The observer to dispatch signals to.</param>
        public void Subscribe(ISignalObserver <T> observer)
        {
            ValidationHelper.RequireNonNullRef(observer, nameof(observer));

            var parent = new PublishDisposable(observer, this);

            observer.OnSubscribe(parent);
            if (Add(parent))
            {
                if (parent.IsDisposed())
                {
                    Remove(parent);
                }
            }
            else
            {
                var ex = error;

                if (ex != ExceptionHelper.TERMINATED)
                {
                    parent.OnError(ex);
                }
                else
                {
                    parent.OnCompleted();
                }
            }
        }
        void Remove(PublishDisposable inner)
        {
            for (; ;)
            {
                var a = Volatile.Read(ref observers);
                var n = a.Length;
                if (n == 0)
                {
                    break;
                }
                int j = Array.IndexOf(a, inner);
                if (j < 0)
                {
                    break;
                }
                var b = default(PublishDisposable[]);

                if (n == 1)
                {
                    if (refCount)
                    {
                        if (Interlocked.CompareExchange(ref observers, Terminated, a) == a)
                        {
                            DisposableHelper.Dispose(ref upstream);
                            break;
                        }
                        continue;
                    }

                    b = Empty;
                }
                else
                {
                    b = new PublishDisposable[n - 1];
                    Array.Copy(a, 0, b, 0, j);
                    Array.Copy(a, j + 1, b, j, n - j - 1);
                }
                if (Interlocked.CompareExchange(ref observers, b, a) == a)
                {
                    break;
                }
            }
        }
 bool Add(PublishDisposable inner)
 {
     for (; ;)
     {
         var a = Volatile.Read(ref observers);
         if (a == Terminated)
         {
             return(false);
         }
         var n = a.Length;
         var b = new PublishDisposable[n + 1];
         Array.Copy(a, 0, b, 0, n);
         b[n] = inner;
         if (Interlocked.CompareExchange(ref observers, b, a) == a)
         {
             return(true);
         }
     }
 }