コード例 #1
0
    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);
            }
        });
    }
コード例 #2
0
    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);
        });
    }
コード例 #3
0
    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);
        });
    }
コード例 #4
0
        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;
        }
コード例 #5
0
 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)));
     });
 }
コード例 #6
0
 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));
     });
 }
コード例 #7
0
 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);
         });
     });
 }
コード例 #8
0
 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);
         });
     });
 }
コード例 #9
0
    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));
    }
コード例 #10
0
    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);
        }
    }
コード例 #11
0
    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);
        });
    }
コード例 #12
0
    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;
        });
    }
コード例 #13
0
 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);
     });
 }
コード例 #14
0
    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);
        });
    }
コード例 #15
0
    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);
        });
    }
コード例 #16
0
    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);
        });
    }
コード例 #17
0
    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);
        });
    }
コード例 #18
0
        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;
        }
コード例 #19
0
    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);
 }
コード例 #21
0
#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);