/// <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; }
/// <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>(); } }
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()); } } }
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; } } }
/// <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); }
/// <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)); } } }
internal void OnRemovedFromCollection(JoinableTaskCollection collection) { Requires.NotNull(collection, nameof(collection)); this.collectionMembership.Remove(collection); }
internal void OnAddedToCollection(JoinableTaskCollection collection) { Requires.NotNull(collection, nameof(collection)); this.collectionMembership.Add(collection); }