/// <summary>
            /// Initializes a new instance of the <see cref="JoinRelease"/> struct.
            /// </summary>
            /// <param name="jobCollection">The collection of joinable tasks that has been joined.</param>
            /// <param name="joiner">The instance that created this value.</param>
            internal JoinRelease(JoinableTaskCollection jobCollection, JoinableTask joiner)
            {
                Requires.NotNull(jobCollection, nameof(jobCollection));
                Requires.NotNull(joiner, nameof(joiner));

                this.joinedJobCollection = jobCollection;
                this.joinedJob           = null;
                this.joiner = joiner;
            }
            /// <summary>
            /// Cancels the <see cref="Join"/> operation.
            /// </summary>
            public void Dispose()
            {
                if (this.joinedJob != null)
                {
                    this.joinedJob.RemoveDependency(this.joiner);
                    this.joinedJob = null;
                }

                if (this.joinedJobCollection != null)
                {
                    this.joinedJobCollection.Disjoin(this.joiner);
                    this.joinedJobCollection = null;
                }

                this.joiner = null;
            }
Exemple #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ProgressWithCompletion{T}" /> class.
 /// </summary>
 /// <param name="handler">
 /// A handler to invoke for each reported progress value.
 /// It is possible that this handler instance could be invoked concurrently with itself.
 /// </param>
 /// <param name="joinableTaskFactory">A <see cref="JoinableTaskFactory"/> instance that can be used to mitigate deadlocks when <see cref="WaitAsync(CancellationToken)"/> is called and the <paramref name="handler"/> requires the main thread.</param>
 public ProgressWithCompletion(Func <T, Task> handler, JoinableTaskFactory joinableTaskFactory)
 {
     Requires.NotNull(handler, nameof(handler));
     this.handler = handler;
     if (joinableTaskFactory != null)
     {
         this.joinableTaskFactory      = joinableTaskFactory;
         this.outstandingJoinableTasks = joinableTaskFactory.Context.CreateCollection();
         this.createdOnMainThread      = joinableTaskFactory.Context.IsOnMainThread;
     }
     else
     {
         this.syncObject       = new object();
         this.taskFactory      = new TaskFactory(SynchronizationContext.Current != null ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Default);
         this.outstandingTasks = new HashSet <Task>();
     }
 }
Exemple #4
0
        public static async Task <T> ExecuteWithinLockAsync <T>(this SemaphoreSlim semaphore, JoinableTaskCollection collection, Func <T> func, CancellationToken cancellationToken = default)
        {
            // Join the caller to our collection, so that if the lock is already held by another task that needs UI
            // thread access we don't deadlock if we're also being waited on by the UI thread. For example, when CPS
            // is draining critical tasks and is waiting us.
            using (collection.Join())
            {
                await semaphore.WaitAsync(cancellationToken);

                using (new SemaphoreDisposer(semaphore))
                {
                    return(func());
                }
            }
        }
Exemple #5
0
        public static async Task ExecuteWithinLockAsync(this SemaphoreSlim semaphore, JoinableTaskCollection collection, JoinableTaskFactory factory, Func <Task> task, CancellationToken cancellationToken = default)
        {
            // Join the caller to our collection, so that if the lock is already held by another task that needs UI
            // thread access we don't deadlock if we're also being waited on by the UI thread. For example, when CPS
            // is draining critical tasks and is waiting us.
            using (collection.Join())
            {
                await semaphore.WaitAsync(cancellationToken);

                using (new SemaphoreDisposer(semaphore))
                {
                    // We do an inner JoinableTaskFactory.RunAsync here to workaround
                    // https://github.com/Microsoft/vs-threading/issues/132
                    JoinableTask joinableTask = factory.RunAsync(task);

                    await joinableTask.Task;
                }
            }
        }
Exemple #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ReentrantSemaphore"/> class.
 /// </summary>
 /// <param name="initialCount">The initial number of concurrent operations to allow.</param>
 /// <param name="joinableTaskContext">The <see cref="JoinableTaskContext"/> to use to mitigate deadlocks.</param>
 /// <devremarks>
 /// This is private protected so that others cannot derive from this type but we can within the assembly.
 /// </devremarks>
 private protected ReentrantSemaphore(int initialCount, JoinableTaskContext joinableTaskContext)
 {
     this.joinableTaskCollection = joinableTaskContext?.CreateCollection();
     this.joinableTaskFactory    = joinableTaskContext?.CreateFactory(this.joinableTaskCollection);
     this.semaphore = new AsyncSemaphore(initialCount);
 }
Exemple #7
0
 /// <summary>
 /// Creates a joinable task factory that automatically adds all created tasks
 /// to a collection that can be jointly joined.
 /// </summary>
 /// <param name="collection">The collection that all tasks should be added to.</param>
 public virtual JoinableTaskFactory CreateFactory(JoinableTaskCollection collection)
 {
     return(this.context.CreateFactory(collection));
 }
 public static async Task ExecuteWithinLockAsync(this SemaphoreSlim semaphore, JoinableTaskCollection collection, JoinableTaskFactory factory, Action action)
 {
     // Join the caller to our collection, so that if the lock is already held by another task that needs UI
     // thread access we don't deadlock if we're also being waited on by the UI thread. For example, when CPS
     // is draining critical tasks and is waiting us.
     using (collection.Join())
     {
         using (await semaphore.DisposableWaitAsync().ConfigureAwait(false))
         {
             action();
         }
     }
 }
        public static async Task <T> ExecuteWithinLockAsync <T>(this SemaphoreSlim semaphore, JoinableTaskCollection collection, JoinableTaskFactory factory, Func <Task <T> > task)
        {
            // Join the caller to our collection, so that if the lock is already held by another task that needs UI
            // thread access we don't deadlock if we're also being waited on by the UI thread. For example, when CPS
            // is draining critical tasks and is waiting us.
            using (collection.Join())
            {
                using (await semaphore.DisposableWaitAsync().ConfigureAwait(false))
                {
                    // We do an inner JoinableTaskFactory.RunAsync here to workaround
                    // https://github.com/Microsoft/vs-threading/issues/132
                    JoinableTask <T> joinableTask = factory.RunAsync(task);

                    return(await joinableTask.Task
                           .ConfigureAwait(false));
                }
            }
        }
Exemple #10
0
 internal void OnRemovedFromCollection(JoinableTaskCollection collection)
 {
     Requires.NotNull(collection, nameof(collection));
     this.collectionMembership.Remove(collection);
 }
Exemple #11
0
 internal void OnAddedToCollection(JoinableTaskCollection collection)
 {
     Requires.NotNull(collection, nameof(collection));
     this.collectionMembership.Add(collection);
 }