Esempio n. 1
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());
                }));
            }
Esempio n. 2
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);
            }