Example #1
0
            public void OnCancelled(ForwardingConsumer forwardingConsumer)
            {
                lock (_gate)
                {
                    // Check for late callbacks
                    if (_forwardingConsumer != forwardingConsumer)
                    {
                        return;
                    }

                    _forwardingConsumer       = null;
                    _multiplexProducerContext = null;
                    CloseSafely(_lastIntermediateResult);
                    _lastIntermediateResult = default(T);
                }

                StartInputProducerIfHasAttachedConsumers();
            }
Example #2
0
            /// <summary>
            /// Starts next producer if it is not started yet and there is
            /// at least one Consumer waiting for the data. If all consumers
            /// are cancelled, then this multiplexer is removed from _request
            /// map to clean up.
            /// </summary>
            internal void StartInputProducerIfHasAttachedConsumers()
            {
                BaseProducerContext multiplexProducerContext;
                ForwardingConsumer  forwardingConsumer;

                lock (_gate)
                {
                    Preconditions.CheckArgument(_multiplexProducerContext == null);
                    Preconditions.CheckArgument(_forwardingConsumer == null);

                    // Cleanup if all consumers have been cancelled before
                    // this method was called
                    if (_consumerContextPairs.IsEmpty)
                    {
                        _parent.RemoveMultiplexer(_key, this);
                        return;
                    }

                    var iterator = _consumerContextPairs.GetEnumerator();
                    iterator.MoveNext();
                    IProducerContext producerContext = iterator.Current.Key.Item2;
                    _multiplexProducerContext = new BaseProducerContext(
                        producerContext.ImageRequest,
                        producerContext.Id,
                        producerContext.Listener,
                        producerContext.CallerContext,
                        producerContext.LowestPermittedRequestLevel,
                        ComputeIsPrefetch(),
                        ComputeIsIntermediateResultExpected(),
                        ComputePriority());

                    _forwardingConsumer      = new ForwardingConsumer(this);
                    multiplexProducerContext = _multiplexProducerContext;
                    forwardingConsumer       = _forwardingConsumer;
                }

                _inputProducer.ProduceResults(
                    forwardingConsumer,
                    multiplexProducerContext);
            }
Example #3
0
            /// <summary>
            /// Register callbacks to be called when cancellation of consumer
            /// is requested, or if the prefetch status of the consumer changes.
            /// </summary>
            private void AddCallbacks(
                Tuple <IConsumer <T>, IProducerContext> consumerContextPair,
                IProducerContext producerContext)
            {
                producerContext.AddCallbacks(
                    new BaseProducerContextCallbacks(
                        () =>
                {
                    BaseProducerContext contextToCancel = null;
                    IList <IProducerContextCallbacks> isPrefetchCallbacks = null;
                    IList <IProducerContextCallbacks> priorityCallbacks   = null;
                    IList <IProducerContextCallbacks> isIntermediateResultExpectedCallbacks = null;
                    bool pairWasRemoved = false;

                    lock (_gate)
                    {
                        object val     = default(object);
                        pairWasRemoved = _consumerContextPairs.TryRemove(consumerContextPair, out val);
                        if (pairWasRemoved)
                        {
                            if (_consumerContextPairs.IsEmpty)
                            {
                                contextToCancel = _multiplexProducerContext;
                            }
                            else
                            {
                                isPrefetchCallbacks = UpdateIsPrefetch();
                                priorityCallbacks   = UpdatePriority();
                                isIntermediateResultExpectedCallbacks = UpdateIsIntermediateResultExpected();
                            }
                        }
                    }

                    BaseProducerContext.CallOnIsPrefetchChanged(isPrefetchCallbacks);
                    BaseProducerContext.CallOnPriorityChanged(priorityCallbacks);
                    BaseProducerContext.CallOnIsIntermediateResultExpectedChanged(
                        isIntermediateResultExpectedCallbacks);

                    if (contextToCancel != null)
                    {
                        contextToCancel.Cancel();
                    }

                    if (pairWasRemoved)
                    {
                        consumerContextPair.Item1.OnCancellation();
                    }
                },
                        () =>
                {
                    BaseProducerContext.CallOnIsPrefetchChanged(UpdateIsPrefetch());
                },
                        () =>
                {
                    BaseProducerContext.CallOnIsIntermediateResultExpectedChanged(
                        UpdateIsIntermediateResultExpected());
                },
                        () =>
                {
                    BaseProducerContext.CallOnPriorityChanged(UpdatePriority());
                }));
            }
Example #4
0
            /// <summary>
            /// Tries to add consumer to set of consumers participating in
            /// multiplexing. If successful and appropriate intermediate
            /// result is already known, then it will be passed to the
            /// consumer.
            ///
            /// <para />This function will fail and return false if the
            /// multiplexer is not present in _multiplexers map.
            /// </summary>
            /// <returns>
            /// true if consumer was added successfully.
            /// </returns>
            internal bool AddNewConsumer(
                IConsumer <T> consumer,
                IProducerContext producerContext)
            {
                var consumerContextPair =
                    new Tuple <IConsumer <T>, IProducerContext>(consumer, producerContext);
                T lastIntermediateResult;
                IList <IProducerContextCallbacks> prefetchCallbacks;
                IList <IProducerContextCallbacks> priorityCallbacks;
                IList <IProducerContextCallbacks> intermediateResultsCallbacks;
                float lastProgress;

                // Check if Multiplexer is still in _multiplexers map, and if so
                // add new consumer. Also store current intermediate result - we
                // will notify consumer after acquiring appropriate lock.
                lock (_gate)
                {
                    if (_parent.GetExistingMultiplexer(_key) != this)
                    {
                        return(false);
                    }

                    _consumerContextPairs.TryAdd(consumerContextPair, new object());
                    prefetchCallbacks            = UpdateIsPrefetch();
                    priorityCallbacks            = UpdatePriority();
                    intermediateResultsCallbacks = UpdateIsIntermediateResultExpected();
                    lastIntermediateResult       = _lastIntermediateResult;
                    lastProgress = _lastProgress;
                }

                BaseProducerContext.CallOnIsPrefetchChanged(prefetchCallbacks);
                BaseProducerContext.CallOnPriorityChanged(priorityCallbacks);
                BaseProducerContext.CallOnIsIntermediateResultExpectedChanged(intermediateResultsCallbacks);

                lock (consumerContextPair)
                {
                    // Check if last result changed in the mean time.
                    // In such case we should not propagate it
                    lock (_gate)
                    {
                        if (!Equals(lastIntermediateResult, _lastIntermediateResult))
                        {
                            lastIntermediateResult = default(T);
                        }
                        else if (lastIntermediateResult != null)
                        {
                            lastIntermediateResult = _parent.CloneOrNull(lastIntermediateResult);
                        }
                    }

                    if (lastIntermediateResult != null)
                    {
                        if (lastProgress > 0)
                        {
                            consumer.OnProgressUpdate(lastProgress);
                        }

                        consumer.OnNewResult(lastIntermediateResult, false);
                        CloseSafely(lastIntermediateResult);
                    }
                }

                AddCallbacks(consumerContextPair, producerContext);
                return(true);
            }