예제 #1
0
            public void resultReceived(CalculationTarget target, CalculationResult calculationResult)
            {
//JAVA TO C# CONVERTER WARNING: Java wildcard generics have no direct equivalent in .NET:
//ORIGINAL LINE: com.opengamma.strata.collect.result.Result<?> result = calculationResult.getResult();
                Result <object> result = calculationResult.Result;
//JAVA TO C# CONVERTER WARNING: Java wildcard generics have no direct equivalent in .NET:
//ORIGINAL LINE: com.opengamma.strata.collect.result.Result<?> unwrappedResult = unwrapScenarioResult(result);
                Result <object>   unwrappedResult            = unwrapScenarioResult(result);
                CalculationResult unwrappedCalculationResult = calculationResult.withResult(unwrappedResult);

                @delegate.resultReceived(target, unwrappedCalculationResult);
            }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Accepts a calculation result and delivers it to the listener
        /// <para>
        /// This method can be invoked concurrently by multiple threads.
        /// Only one of them will invoke the listener directly to ensure that
        /// it is not accessed concurrently by multiple threads.
        /// </para>
        /// <para>
        /// The other threads do not block while the listener is invoked. They
        /// add their results to a queue and return quickly. Their results are
        /// delivered by the thread invoking the listener.
        ///
        /// </para>
        /// </summary>
        /// <param name="result"> the result of a calculation </param>
        public override void accept(CalculationResults result)
        {
            CalculationResults nextResult;

            // Multiple calculation threads can try to acquire this lock at the same time.
            // The thread which acquires the lock will set the executing flag and proceed into
            // the body of the method.
            // If another thread acquires the lock while the first thread is executing it will
            // add an item to the queue and return.
            // The lock also ensures the state of the executing flag and the queue are visible
            // to any thread acquiring the lock.
            @lock.@lock();
            try
            {
                if (executing)
                {
                    // Another thread is already invoking the listener. Add the result to
                    // the queue and return. The other thread will ensure the queued results
                    // are delivered.
                    queue.AddLast(result);
                    return;
                }
                else
                {
                    // There is no thread invoking the listener. Set the executing flag to
                    // ensure no other thread passes this point and invoke the listener.
                    executing  = true;
                    nextResult = result;
                }
            }
            finally
            {
                @lock.unlock();
            }

            // The logic in the block above guarantees that there will never be more than one thread in the
            // rest of the method below this point.

            // Loop until the nextResult and all the results from the queue have been delivered
            for (;;)
            {
                // The logic above means this lock is never contended; the executing flag means
                // only one thread will ever be in this loop at any given time.
                // This lock is required to ensure any state changes in the listener are visible to all threads
                listenerLock.@lock();
                try
                {
                    // Invoke the listener while not protected by lock. This allows other threads
                    // to queue results while this thread is delivering them to the listener.
                    foreach (CalculationResult cell in nextResult.Cells)
                    {
                        listener.resultReceived(nextResult.Target, cell);
                    }
                }
                catch (Exception e)
                {
                    log.warn("Exception invoking listener.resultReceived", e);
                }
                finally
                {
                    listenerLock.unlock();
                }

                // The following code must be executed whilst holding the lock to guarantee any changes
                // to the executing flag and to the state of the queue are visible to all threads
                @lock.@lock();
                try
                {
                    if (++tasksReceived == tasksExpected)
                    {
                        // The expected number of results have been received, inform the listener.
                        // The listener lock must be acquired to ensure any state changes in the listener are
                        // visible to all threads
                        listenerLock.@lock();
                        try
                        {
                            listener.calculationsComplete();
                        }
                        catch (Exception e)
                        {
                            log.warn("Exception invoking listener.calculationsComplete", e);
                        }
                        finally
                        {
                            listenerLock.unlock();
                        }
                        return;
                    }
                    else if (queue.Count == 0)
                    {
                        // There are no more results to deliver. Unset the executing flag and return.
                        // This allows the next calling thread to deliver results.
                        executing = false;
                        return;
                    }
                    else
                    {
                        // There are results on the queue. This means another thread called accept(),
                        // added a result to the queue and returned while this thread was invoking the listener.
                        // This thread must deliver the results from the queue.
                        nextResult = queue.RemoveFirst();
                    }
                }
                finally
                {
                    @lock.unlock();
                }
            }
        }