コード例 #1
0
ファイル: CacheNeedle.cs プロジェクト: pocketgems/Theraot
 protected virtual void Initialize(Action beforeInitialize)
 {
     if (beforeInitialize == null)
     {
         throw new ArgumentNullException("beforeInitialize");
     }
     if (ThreadingHelper.VolatileRead(ref _valueFactory) == null)
     {
         // If unable to initialize do nothing
         // This happens if
         // - initialization is done
         // - ReleaseValueFactory was called
         // Even if ReleaseValueFactory was called before initialization,
         // _target can still be set by SetTargetValue or the Value property
         return;
     }
     try
     {
         beforeInitialize.Invoke();
     }
     finally
     {
         InitializeExtracted();
     }
 }
コード例 #2
0
        private ManualResetEvent TryGetWaitHandleExtracted()
        {
            var handle = ThreadingHelper.VolatileRead(ref _handle);

            if (handle != null)
            {
                if (Thread.VolatileRead(ref _requested) == 2)
                {
                    return(handle);
                }
                handle.Close();
            }
            Thread.VolatileWrite(ref _requested, -1);
            throw new ObjectDisposedException(GetType().FullName);
        }
コード例 #3
0
 internal void FinishThreadAbortedTask(bool exceptionAdded, bool delegateRan)
 {
     if (Interlocked.CompareExchange(ref _threadAbortedmanaged, 1, 0) == 0)
     {
         var exceptionsHolder = ThreadingHelper.VolatileRead(ref _exceptionsHolder);
         if (exceptionsHolder == null)
         {
             return;
         }
         if (exceptionAdded)
         {
             exceptionsHolder.MarkAsHandled(false);
         }
         Finish(delegateRan);
     }
 }
コード例 #4
0
        /// <summary>
        /// This is to be called just before the task does its final state transition.
        /// It traverses the list of exceptional children, and appends their aggregate exceptions into this one's exception list
        /// </summary>
        internal void AddExceptionsFromChildren()
        {
            // In rare occurences during AppDomainUnload() processing, it is possible for this method to be called
            // simultaneously on the same task from two different contexts.  This can result in m_exceptionalChildren
            // being nulled out while it is being processed, which could lead to a NullReferenceException.  To
            // protect ourselves, we'll cache m_exceptionalChildren in a local variable.
            var tmp = ThreadingHelper.VolatileRead(ref _exceptionalChildren);

            if (tmp != null)
            {
                // This lock is necessary because even though AddExceptionsFromChildren is last to execute, it may still
                // be racing with the code segment at the bottom of Finish() that prunes the exceptional child array.
                lock (tmp)
                {
                    foreach (var task in tmp)
                    {
                        // Ensure any exceptions thrown by children are added to the parent.
                        // In doing this, we are implicitly marking children as being "handled".
                        Contract.Assert(task.IsCompleted, "Expected all tasks in list to be completed");
                        if (task.IsFaulted && !task.IsExceptionObservedByParent)
                        {
                            var exceptionsHolder = ThreadingHelper.VolatileRead(ref task._exceptionsHolder);
                            if (exceptionsHolder == null)
                            {
                                Contract.Assert(false);
                            }
                            else
                            {
                                // No locking necessary since child task is finished adding exceptions
                                // and concurrent CreateExceptionObject() calls do not constitute
                                // a concurrency hazard.
                                AddException(exceptionsHolder.CreateExceptionObject(false, null));
                            }
                        }
                    }
                }

                // Reduce memory pressure by getting rid of the array
                ThreadingHelper.VolatileWrite(ref _exceptionalChildren, null);
            }
        }
コード例 #5
0
        internal void Finish(bool userDelegateExecuted)
        {
            if (!userDelegateExecuted)
            {
                // delegate didn't execute => no children. We can safely call the remaining finish stages
                FinishStageTwo();
            }
            else
            {
                // Reaching this sub clause means there may be remaining active children,
                // and we could be racing with one of them to call FinishStageTwo().
                // So whoever does the final Interlocked.Dec is responsible to finish.
                if ((_completionCountdown == 1 && !IsSelfReplicatingRoot) || Interlocked.Decrement(ref _completionCountdown) == 0)
                {
                    FinishStageTwo();
                }
                else
                {
                    // Apparently some children still remain. It will be up to the last one to process the completion of this task on their own thread.
                    // We will now yield the thread back to ThreadPool. Mark our state appropriately before getting out.

                    // We have to use an atomic update for this and make sure not to overwrite a final state,
                    // because at this very moment the last child's thread may be concurrently completing us.
                    // Otherwise we risk overwriting the TaskStatus which may have been set by that child task.

                    Interlocked.CompareExchange(ref _status, (int)TaskStatus.WaitingForChildrenToComplete, (int)TaskStatus.Running);
                }

                // Now is the time to prune exceptional children. We'll walk the list and removes the ones whose exceptions we might have observed after they threw.
                // we use a local variable for exceptional children here because some other thread may be nulling out _exceptionalChildren
                var exceptionalChildren = ThreadingHelper.VolatileRead(ref _exceptionalChildren);

                if (exceptionalChildren != null)
                {
                    lock (exceptionalChildren)
                    {
                        exceptionalChildren.RemoveAll(_isExceptionObservedByParentPredicate); // RemoveAll has better performance than doing it ourselves
                    }
                }
            }
        }
コード例 #6
0
        internal void ProcessChildCompletion(Task childTask)
        {
            Contract.Requires(childTask != null);
            Contract.Requires(childTask.IsCompleted, "ProcessChildCompletion was called for an uncompleted task");

            Contract.Assert(childTask._parent == this, "ProcessChildCompletion should only be called for a child of this task");

            // if the child threw and we haven't observed it we need to save it for future reference
            if (childTask.IsFaulted && !childTask.IsExceptionObservedByParent)
            {
                // Lazily initialize the child exception list
                if (ThreadingHelper.VolatileRead(ref _exceptionalChildren) == null)
                {
                    Interlocked.CompareExchange(ref _exceptionalChildren, new List <Task>(), null);
                }

                // In rare situations involving AppDomainUnload, it's possible (though unlikely) for FinishStageTwo() to be called
                // multiple times for the same task.  In that case, AddExceptionsFromChildren() could be nulling m_exceptionalChildren
                // out at the same time that we're processing it, resulting in a NullReferenceException here.  We'll protect
                // ourselves by caching m_exceptionChildren in a local variable.
                var tmp = ThreadingHelper.VolatileRead(ref _exceptionalChildren);
                if (tmp != null)
                {
                    lock (tmp)
                    {
                        tmp.Add(childTask);
                    }
                }
            }

            if (Interlocked.Decrement(ref _completionCountdown) == 0)
            {
                // This call came from the final child to complete, and apparently we have previously given up this task's right to complete itself.
                // So we need to invoke the final finish stage.

                FinishStageTwo();
            }
        }
コード例 #7
0
 public static T Read <T>(ref T location)
     where T : class
 {
     return(ThreadingHelper.VolatileRead(ref location));
 }
コード例 #8
0
        /// <summary>
        /// Returns a list of exceptions by aggregating the holder's contents. Or null if
        /// no exceptions have been thrown.
        /// </summary>
        /// <param name="includeTaskCanceledExceptions">Whether to include a TCE if cancelled.</param>
        /// <returns>An aggregate exception, or null if no exceptions have been caught.</returns>
        private AggregateException GetExceptions(bool includeTaskCanceledExceptions)
        {
            //
            // WARNING: The Task/Task<TResult>/TaskCompletionSource classes
            // have all been carefully crafted to insure that GetExceptions()
            // is never called while AddException() is being called.  There
            // are locks taken on m_contingentProperties in several places:
            //
            // -- Task<TResult>.TrySetException(): The lock allows the
            //    task to be set to Faulted state, and all exceptions to
            //    be recorded, in one atomic action.
            //
            // -- Task.Exception_get(): The lock ensures that Task<TResult>.TrySetException()
            //    is allowed to complete its operation before Task.Exception_get()
            //    can access GetExceptions().
            //
            // -- Task.ThrowIfExceptional(): The lock insures that Wait() will
            //    not attempt to call GetExceptions() while Task<TResult>.TrySetException()
            //    is in the process of calling AddException().
            //
            // For "regular" tasks, we effectively keep AddException() and GetException()
            // from being called concurrently by the way that the state flows.  Until
            // a Task is marked Faulted, Task.Exception_get() returns null.  And
            // a Task is not marked Faulted until it and all of its children have
            // completed, which means that all exceptions have been recorded.
            //
            // It might be a lot easier to follow all of this if we just required
            // that all calls to GetExceptions() and AddExceptions() were made
            // under a lock on m_contingentProperties.  But that would also
            // increase our lock occupancy time and the frequency with which we
            // would need to take the lock.
            //
            // If you add a call to GetExceptions() anywhere in the code,
            // please continue to maintain the invariant that it can't be
            // called when AddException() is being called.
            //

            // We'll lazily create a TCE if the task has been canceled.
            Exception canceledException = null;

            if (includeTaskCanceledExceptions && IsCanceled)
            {
                // Backcompat:
                // Ideally we'd just use the cached OCE from this.GetCancellationExceptionDispatchInfo()
                // here.  However, that would result in a potentially breaking change from .NET 4, which
                // has the code here that throws a new exception instead of the original, and the EDI
                // may not contain a TCE, but an OCE or any OCE-derived type, which would mean we'd be
                // propagating an exception of a different type.
                canceledException = new TaskCanceledException(this);
            }

            var exceptionsHolder = ThreadingHelper.VolatileRead(ref _exceptionsHolder);

            if (exceptionsHolder != null && exceptionsHolder.ContainsFaultList)
            {
                // No need to lock around this, as other logic prevents the consumption of exceptions
                // before they have been completely processed.
                return(_exceptionsHolder.CreateExceptionObject(false, canceledException));
            }
            if (canceledException != null)
            {
                // No exceptions, but there was a cancelation. Aggregate and return it.
                return(new AggregateException(canceledException));
            }

            return(null);
        }
コード例 #9
0
ファイル: CacheNeedle.cs プロジェクト: pocketgems/Theraot
        private void InitializeExtracted()
        {
back:
            var valueFactory = Interlocked.Exchange(ref _valueFactory, null);

            if (valueFactory == null)
            {
                // Many threads may enter here
                // Prevent reentry
                if (_initializerThread == Thread.CurrentThread)
                {
                    throw new InvalidOperationException();
                }
                var waitHandle = _waitHandle.Value;
                // While _waitHandle.Value is not null it means that we have to wait initialization to complete
                if (waitHandle != null)
                {
                    try
                    {
                        // Another thread may have called ReleaseWaitHandle just before the next instruction
                        waitHandle.Wait();
                        // Finished waiting...
                        if (ThreadingHelper.VolatileRead(ref _valueFactory) != null)
                        {
                            // There was an error in the initialization, go back
                            goto back;
                        }
                        ReleaseWaitHandle();
                    }
                    catch (ObjectDisposedException exception)
                    {
                        // Came late to the party, initialization is done
                        GC.KeepAlive(exception);
                    }
                }
            }
            else
            {
                // Only one thread enters here
                _initializerThread = Thread.CurrentThread;
                try
                {
                    // Initialize from the value factory
                    SetTargetValue(valueFactory.Invoke());
                    // Initialization done, let any wating thread go
                    ReleaseWaitHandle();
                }
                catch (Exception exception)
                {
                    // There was an error during initialization
                    // Set error state
                    SetTargetError(exception);
                    // Restore the valueFactory
                    Interlocked.CompareExchange(ref _valueFactory, valueFactory, null);
                    // Let any waiting threads go, but don't get rid of the wait handle
                    _waitHandle.Value.Set();
                    throw;
                }
                finally
                {
                    _initializerThread = null;
                }
            }
        }