public void Uncontested(int initialCount) { this.ExecuteOnDispatcher(async delegate { this.semaphore = this.CreateSemaphore(initialCount: initialCount); var releasers = Enumerable.Range(0, initialCount).Select(i => new AsyncManualResetEvent()).ToArray(); var operations = new Task[initialCount]; for (int i = 0; i < 5; i++) { // Fill the semaphore to its capacity for (int j = 0; j < initialCount; j++) { int k = j; // Capture j, as it will increment operations[j] = this.semaphore.ExecuteAsync(() => releasers[k].WaitAsync(), this.TimeoutToken); } var releaseSequence = Enumerable.Range(0, initialCount); // We'll test both releasing in FIFO and LIFO order. if (i % 2 == 0) { releaseSequence = releaseSequence.Reverse(); } foreach (int j in releaseSequence) { releasers[j].Set(); } await Task.WhenAll(operations).WithCancellation(this.TimeoutToken); } }); }
public void ExecuteAsync_OfT_InvokesDelegateInOriginalContext_WithContention(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); int originalThreadId = Environment.CurrentManagedThreadId; this.ExecuteOnDispatcher(async delegate { var releaseHolder = new AsyncManualResetEvent(); var holder = this.semaphore.ExecuteAsync(() => releaseHolder.WaitAsync()); bool executed = false; var waiter = this.semaphore.ExecuteAsync( delegate { Assert.Equal(originalThreadId, Environment.CurrentManagedThreadId); executed = true; return(new ValueTask <int>(5)); }, this.TimeoutToken); releaseHolder.Set(); int result = await waiter.AsTask().WithCancellation(this.TimeoutToken); Assert.Equal(5, result); Assert.True(executed); }); }
public void ExecuteAsync_Contested(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); this.ExecuteOnDispatcher(async delegate { var firstEntered = new AsyncManualResetEvent(); var firstRelease = new AsyncManualResetEvent(); var secondEntered = new AsyncManualResetEvent(); var firstOperation = this.semaphore.ExecuteAsync( async delegate { firstEntered.Set(); await firstRelease; }, this.TimeoutToken); var secondOperation = this.semaphore.ExecuteAsync( delegate { secondEntered.Set(); return(TplExtensions.CompletedTask); }, this.TimeoutToken); await firstEntered.WaitAsync().WithCancellation(this.TimeoutToken); await Assert.ThrowsAsync <TimeoutException>(() => secondEntered.WaitAsync().WithTimeout(ExpectedTimeout)); firstRelease.Set(); await secondEntered.WaitAsync().WithCancellation(this.TimeoutToken); await Task.WhenAll(firstOperation, secondOperation); }); }
internal InfiniteScrollList(Lazy <JoinableTaskFactory> joinableTaskFactory) { if (joinableTaskFactory == null) { throw new ArgumentNullException(nameof(joinableTaskFactory)); } _joinableTaskFactory = joinableTaskFactory; InitializeComponent(); _list.ItemsLock = ReentrantSemaphore.Create( initialCount: 1, joinableTaskContext: _joinableTaskFactory.Value.Context, mode: ReentrantSemaphore.ReentrancyMode.Stack); BindingOperations.EnableCollectionSynchronization(Items, _list.ItemsLock); ItemsView = new CollectionViewSource() { Source = Items }.View; DataContext = ItemsView; CheckBoxesEnabled = false; _loadingStatusIndicator.PropertyChanged += LoadingStatusIndicator_PropertyChanged; }
public void Semaphore_PreCanceledRequest_DoesNotEnterSemaphore(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); this.ExecuteOnDispatcher(async delegate { await Assert.ThrowsAnyAsync <OperationCanceledException>(() => this.semaphore.ExecuteAsync(() => TplExtensions.CompletedTask, new CancellationToken(true))); }); }
public void ExecuteAsync_NullDelegate(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); this.ExecuteOnDispatcher(async delegate { await Assert.ThrowsAsync <ArgumentNullException>(() => this.semaphore.ExecuteAsync(null, this.TimeoutToken)); }); }
public void ReentrancyRejected_WhenNotAllowed() { this.semaphore = this.CreateSemaphore(ReentrantSemaphore.ReentrancyMode.NotAllowed); this.ExecuteOnDispatcher(async delegate { await this.semaphore.ExecuteAsync(async delegate { await Assert.ThrowsAsync <InvalidOperationException>(() => this.semaphore.ExecuteAsync(() => TplExtensions.CompletedTask)); Assert.Equal(0, this.semaphore.CurrentCount); }); }); }
public void DisposeWhileHoldingSemaphore(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); this.ExecuteOnDispatcher(async delegate { await this.semaphore.ExecuteAsync(delegate { this.semaphore.Dispose(); return(TplExtensions.CompletedTask); }); }); }
protected override ReentrantSemaphore CreateSemaphore(ReentrantSemaphore.ReentrancyMode mode, int initialCount = 1) { if (this.joinableTaskContext == null) { using (this.Dispatcher.Apply()) { this.joinableTaskContext = new JoinableTaskContext(); } } return(ReentrantSemaphore.Create(initialCount, this.joinableTaskContext, mode)); }
public void SemaphoreOwnershipDoesNotResurrect2(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); AsyncManualResetEvent releaseInheritor1 = new AsyncManualResetEvent(); AsyncManualResetEvent releaseInheritor2 = new AsyncManualResetEvent(); Task innerOperation1 = null; Task innerOperation2 = null; this.ExecuteOnDispatcher(async delegate { await this.semaphore.ExecuteAsync(delegate { innerOperation1 = SemaphoreRecycler1(); innerOperation2 = SemaphoreRecycler2(); return(TplExtensions.CompletedTask); }); releaseInheritor1.Set(); await innerOperation1.WithCancellation(this.TimeoutToken); }); async Task SemaphoreRecycler1() { await releaseInheritor1; Assert.Equal(1, this.semaphore.CurrentCount); await this.semaphore.ExecuteAsync( async delegate { releaseInheritor2.Set(); await Assert.ThrowsAnyAsync <OperationCanceledException>(() => innerOperation2); }, this.TimeoutToken); } async Task SemaphoreRecycler2() { await releaseInheritor2; Assert.Equal(0, this.semaphore.CurrentCount); // Try to enter the semaphore. This should timeout because someone else is holding the semaphore, waiting for us to timeout. await this.semaphore.ExecuteAsync( () => TplExtensions.CompletedTask, new CancellationTokenSource(ExpectedTimeout).Token); } }
public void ReentrancyNotRecognized() { this.semaphore = this.CreateSemaphore(ReentrantSemaphore.ReentrancyMode.NotRecognized); this.ExecuteOnDispatcher(async delegate { Task innerUser = null; await this.semaphore.ExecuteAsync(async delegate { Assert.Equal(0, this.semaphore.CurrentCount); innerUser = this.semaphore.ExecuteAsync(() => TplExtensions.CompletedTask); await Assert.ThrowsAsync <TimeoutException>(() => innerUser.WithTimeout(ExpectedTimeout)); }); await innerUser.WithCancellation(this.TimeoutToken); Assert.Equal(1, this.semaphore.CurrentCount); }); }
public void CancellationAbortsContendedRequest(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); this.ExecuteOnDispatcher(async delegate { var release = new AsyncManualResetEvent(); var holder = this.semaphore.ExecuteAsync(() => release.WaitAsync(), this.TimeoutToken); var cts = CancellationTokenSource.CreateLinkedTokenSource(this.TimeoutToken); var waiter = this.semaphore.ExecuteAsync(() => TplExtensions.CompletedTask, cts.Token); Assert.False(waiter.IsCompleted); cts.Cancel(); await Assert.ThrowsAnyAsync <OperationCanceledException>(() => waiter).WithCancellation(this.TimeoutToken); release.Set(); await holder; }); }
public void Reentrant(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); this.ExecuteOnDispatcher(async delegate { await this.semaphore.ExecuteAsync(async delegate { await this.semaphore.ExecuteAsync(async delegate { await this.semaphore.ExecuteAsync(delegate { return(TplExtensions.CompletedTask); }, this.TimeoutToken); }, this.TimeoutToken); }, this.TimeoutToken); }); }
public void ExecuteAsync_InvokesDelegateInOriginalContext_NoContention(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); int originalThreadId = Environment.CurrentManagedThreadId; this.ExecuteOnDispatcher(async delegate { bool executed = false; await this.semaphore.ExecuteAsync( delegate { Assert.Equal(originalThreadId, Environment.CurrentManagedThreadId); executed = true; return(TplExtensions.CompletedTask); }, this.TimeoutToken); Assert.True(executed); }); }
public void SemaphoreWorkThrows_DoesNotAbandonSemaphore(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); this.ExecuteOnDispatcher(async delegate { await Assert.ThrowsAsync <InvalidOperationException>(async delegate { await this.semaphore.ExecuteAsync( delegate { throw new InvalidOperationException(); }, this.TimeoutToken); }); await this.semaphore.ExecuteAsync(() => TplExtensions.CompletedTask, this.TimeoutToken); }); }
public void SemaphoreAwaitersAreQueued(ReentrantSemaphore.ReentrancyMode mode) { this.ExecuteOnDispatcher(async delegate { this.semaphore = this.CreateSemaphore(mode); var releaseFirstHolder = new AsyncManualResetEvent(); var holder = this.semaphore.ExecuteAsync(() => releaseFirstHolder.WaitAsync()); const int waiterCount = 5; var cts = new CancellationTokenSource[waiterCount]; var waiters = new Task[waiterCount]; var enteredLog = new List <int>(); for (int i = 0; i < waiterCount; i++) { cts[i] = new CancellationTokenSource(); int j = i; waiters[i] = this.semaphore.ExecuteAsync( () => { enteredLog.Add(j); return(TplExtensions.CompletedTask); }, cts[i].Token); } Assert.All(waiters, waiter => Assert.False(waiter.IsCompleted)); const int canceledWaiterIndex = 2; cts[canceledWaiterIndex].Cancel(); await Assert.ThrowsAnyAsync <OperationCanceledException>(() => waiters[canceledWaiterIndex]).WithCancellation(this.TimeoutToken); Assert.Empty(enteredLog); for (int i = 0; i < waiterCount; i++) { Assert.Equal(i == canceledWaiterIndex, waiters[i].IsCompleted); } // Release the first semaphore. releaseFirstHolder.Set(); // Confirm that the rest streamed through, in the right order. await Assert.ThrowsAnyAsync <OperationCanceledException>(() => Task.WhenAll(waiters)).WithCancellation(this.TimeoutToken); Assert.Equal(Enumerable.Range(0, waiterCount).Except(new[] { canceledWaiterIndex }), enteredLog); }); }
public void Nested_StackStyle(ReentrantSemaphore.ReentrancyMode mode) { this.semaphore = this.CreateSemaphore(mode); this.ExecuteOnDispatcher(async delegate { await this.semaphore.ExecuteAsync(async delegate { await this.semaphore.ExecuteAsync(async delegate { await Task.Yield(); Assert.Equal(0, this.semaphore.CurrentCount); }); Assert.Equal(0, this.semaphore.CurrentCount); }); Assert.Equal(1, this.semaphore.CurrentCount); }); }
internal InfiniteScrollList(Lazy <JoinableTaskFactory> joinableTaskFactory) { if (joinableTaskFactory == null) { throw new ArgumentNullException(nameof(joinableTaskFactory)); } _joinableTaskFactory = joinableTaskFactory; InitializeComponent(); _list.ItemsLock = ReentrantSemaphore.Create( initialCount: 1, joinableTaskContext: _joinableTaskFactory.Value.Context, mode: ReentrantSemaphore.ReentrancyMode.Stack); BindingOperations.EnableCollectionSynchronization(Items, _list.ItemsLock); DataContext = Items; CheckBoxesEnabled = false; }
public void Stack_ViolationCaughtAtBothSites() { this.semaphore = this.CreateSemaphore(ReentrantSemaphore.ReentrancyMode.Stack); this.ExecuteOnDispatcher(async delegate { var release1 = new AsyncManualResetEvent(); var release2 = new AsyncManualResetEvent(); Task operation1, operation2 = null; operation1 = this.semaphore.ExecuteAsync(async delegate { operation2 = this.semaphore.ExecuteAsync(async delegate { await release2; }); Assert.Equal(0, this.semaphore.CurrentCount); await release1; }); // Release the outer one first. This should throw because the inner one hasn't been released yet. release1.Set(); await Assert.ThrowsAsync <InvalidOperationException>(() => operation1); // Verify that the semaphore is in a faulted state. Assert.Throws <InvalidOperationException>(() => this.semaphore.CurrentCount); // Release the nested one last, which should similarly throw because its parent is already released. release2.Set(); await Assert.ThrowsAsync <InvalidOperationException>(() => operation2); // Verify that the semaphore is still in a faulted state, and will reject new calls. Assert.Throws <InvalidOperationException>(() => this.semaphore.CurrentCount); await Assert.ThrowsAsync <InvalidOperationException>(() => this.semaphore.ExecuteAsync(() => TplExtensions.CompletedTask)); }); }
protected OnceInitializedOnceDisposedUnderLockAsync(JoinableTaskContextNode joinableTaskContextNode) : base(joinableTaskContextNode) { _semaphore = ReentrantSemaphore.Create(1, joinableTaskContextNode.Context, ReentrantSemaphore.ReentrancyMode.Stack); }
#pragma warning disable VSTHRD012 // Provide JoinableTaskFactory where allowed (we do this in the JTF-aware variant of these tests in a derived class.) protected virtual ReentrantSemaphore CreateSemaphore(ReentrantSemaphore.ReentrancyMode mode = ReentrantSemaphore.ReentrancyMode.NotAllowed, int initialCount = 1) => ReentrantSemaphore.Create(initialCount, mode: mode);