Exemplo n.º 1
0
        private bool TryDequeueSelfOrDependencies(bool onMainThread, ref HashSet <JoinableTask> visited, out SingleExecuteProtector work, out Task tryAgainAfter)
        {
            using (this.Factory.Context.NoMessagePumpSynchronizationContext.Apply())
            {
                lock (this.owner.Context.SyncContextLock)
                {
                    if (this.IsCompleted)
                    {
                        work          = null;
                        tryAgainAfter = null;
                        return(false);
                    }

                    if (this.pendingEventCount > 0)
                    {
                        this.pendingEventCount--;

                        if (this.pendingEventSource != null)
                        {
                            JoinableTask pendingSource;
                            if (this.pendingEventSource.TryGetTarget(out pendingSource) && pendingSource.IsDependingSynchronousTask(this))
                            {
                                var queue = onMainThread ? pendingSource.mainThreadQueue : pendingSource.threadPoolQueue;
                                if (queue != null && !queue.IsCompleted && queue.TryDequeue(out work))
                                {
                                    if (queue.Count == 0)
                                    {
                                        this.pendingEventSource = null;
                                    }

                                    tryAgainAfter = null;
                                    return(true);
                                }
                            }

                            this.pendingEventSource = null;
                        }

                        if (visited == null)
                        {
                            visited = new HashSet <JoinableTask>();
                        }
                        else
                        {
                            visited.Clear();
                        }

                        if (this.TryDequeueSelfOrDependencies(onMainThread, visited, out work))
                        {
                            tryAgainAfter = null;
                            return(true);
                        }
                    }

                    this.pendingEventCount = 0;

                    work          = null;
                    tryAgainAfter = this.QueueNeedProcessEvent;
                    return(false);
                }
            }
        }
Exemplo n.º 2
0
        internal void Post(SendOrPostCallback d, object state, bool mainThreadAffinitized)
        {
            using (this.Factory.Context.NoMessagePumpSynchronizationContext.Apply())
            {
                SingleExecuteProtector       wrapper          = null;
                List <AsyncManualResetEvent> eventsNeedNotify = null; // initialized if we should pulse it at the end of the method
                bool postToFactory = false;

                bool isCompleteRequested;
                bool synchronouslyBlockingMainThread;
                lock (this.owner.Context.SyncContextLock)
                {
                    isCompleteRequested             = this.IsCompleteRequested;
                    synchronouslyBlockingMainThread = this.SynchronouslyBlockingMainThread;
                }

                if (isCompleteRequested)
                {
                    // This job has already been marked for completion.
                    // We need to forward the work to the fallback mechanisms.
                    postToFactory = true;
                }
                else
                {
                    bool mainThreadQueueUpdated       = false;
                    bool backgroundThreadQueueUpdated = false;
                    wrapper = SingleExecuteProtector.Create(this, d, state);

                    if (ThreadingEventSource.Instance.IsEnabled())
                    {
                        ThreadingEventSource.Instance.PostExecutionStart(wrapper.GetHashCode(), mainThreadAffinitized);
                    }

                    if (mainThreadAffinitized && !synchronouslyBlockingMainThread)
                    {
                        wrapper.RaiseTransitioningEvents();
                    }

                    lock (this.owner.Context.SyncContextLock)
                    {
                        if (mainThreadAffinitized)
                        {
                            if (this.mainThreadQueue == null)
                            {
                                this.mainThreadQueue = new ExecutionQueue(this);
                            }

                            // Try to post the message here, but we'll also post to the underlying sync context
                            // so if this fails (because the operation has completed) we'll still get the work
                            // done eventually.
                            this.mainThreadQueue.TryEnqueue(wrapper);
                            mainThreadQueueUpdated = true;
                        }
                        else
                        {
                            if (this.SynchronouslyBlockingThreadPool)
                            {
                                if (this.threadPoolQueue == null)
                                {
                                    this.threadPoolQueue = new ExecutionQueue(this);
                                }

                                backgroundThreadQueueUpdated = this.threadPoolQueue.TryEnqueue(wrapper);
                                if (!backgroundThreadQueueUpdated)
                                {
                                    ThreadPool.QueueUserWorkItem(SingleExecuteProtector.ExecuteOnceWaitCallback, wrapper);
                                }
                            }
                            else
                            {
                                ThreadPool.QueueUserWorkItem(SingleExecuteProtector.ExecuteOnceWaitCallback, wrapper);
                            }
                        }

                        if (mainThreadQueueUpdated || backgroundThreadQueueUpdated)
                        {
                            var tasksNeedNotify = this.GetDependingSynchronousTasks(mainThreadQueueUpdated);
                            if (tasksNeedNotify.Count > 0)
                            {
                                eventsNeedNotify = new List <AsyncManualResetEvent>(tasksNeedNotify.Count);
                                foreach (var taskToNotify in tasksNeedNotify)
                                {
                                    if (taskToNotify.pendingEventSource == null || taskToNotify == this)
                                    {
                                        taskToNotify.pendingEventSource = this.WeakSelf;
                                    }

                                    taskToNotify.pendingEventCount++;
                                    if (taskToNotify.queueNeedProcessEvent != null)
                                    {
                                        eventsNeedNotify.Add(taskToNotify.queueNeedProcessEvent);
                                    }
                                }
                            }
                        }
                    }
                }

                // Notify tasks which can process the event queue.
                if (eventsNeedNotify != null)
                {
                    foreach (var queueEvent in eventsNeedNotify)
                    {
                        queueEvent.PulseAll();
                    }
                }

                // We deferred this till after we release our lock earlier in this method since we're calling outside code.
                if (postToFactory)
                {
                    Assumes.Null(wrapper); // we avoid using a wrapper in this case because this job transferring ownership to the factory.
                    this.Factory.Post(d, state, mainThreadAffinitized);
                }
                else if (mainThreadAffinitized)
                {
                    Assumes.NotNull(wrapper); // this should have been initialized in the above logic.
                    this.owner.PostToUnderlyingSynchronizationContextOrThreadPool(wrapper);

                    foreach (var nestingFactory in this.nestingFactories)
                    {
                        if (nestingFactory != this.owner)
                        {
                            nestingFactory.PostToUnderlyingSynchronizationContextOrThreadPool(wrapper);
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
        private bool TryDequeueSelfOrDependencies(bool onMainThread, HashSet <JoinableTask> visited, out SingleExecuteProtector work)
        {
            Requires.NotNull(visited, nameof(visited));
            Report.IfNot(Monitor.IsEntered(this.owner.Context.SyncContextLock));

            // We only need find the first work item.
            work = null;
            if (visited.Add(this))
            {
                var queue = onMainThread ? this.mainThreadQueue : this.threadPoolQueue;
                if (queue != null && !queue.IsCompleted)
                {
                    queue.TryDequeue(out work);
                }

                if (work == null)
                {
                    if (this.childOrJoinedJobs != null && !this.IsCompleted)
                    {
                        foreach (var item in this.childOrJoinedJobs)
                        {
                            if (item.Key.TryDequeueSelfOrDependencies(onMainThread, visited, out work))
                            {
                                break;
                            }
                        }
                    }
                }
            }

            return(work != null);
        }