Exemple #1
0
        public async Task Uncontested(int initialCount)
        {
            this.lck = new AsyncSemaphore(initialCount);

            var releasers = new AsyncSemaphore.Releaser[initialCount];

            for (int i = 0; i < 5; i++)
            {
                // Fill the semaphore to its capacity
                for (int j = 0; j < initialCount; j++)
                {
                    releasers[j] = await this.lck.EnterAsync();
                }

                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].Dispose();
                }
            }
        }
Exemple #2
0
    public async Task CancelledRequestIsImmediate()
    {
        AsyncSemaphore.Releaser releaser1 = await this.lck.EnterAsync();

        // With the semaphore fully occupied, issue a cancelable request.
        var cts = new CancellationTokenSource();
        Task <AsyncSemaphore.Releaser>?releaser2Task = this.lck.EnterAsync(cts.Token);

        Assert.False(releaser2Task.IsCompleted);

        // Also pend a 3rd request.
        Task <AsyncSemaphore.Releaser>?releaser3Task = this.lck.EnterAsync();

        Assert.False(releaser3Task.IsCompleted);

        // Cancel the second user
        cts.Cancel();
        OperationCanceledException?oce = await Assert.ThrowsAnyAsync <OperationCanceledException>(() => releaser2Task).WithCancellation(this.TimeoutToken);

        Assert.Equal(cts.Token, oce.CancellationToken);

        // Verify that the 3rd user still hasn't gotten in.
        Assert.Equal(0, this.lck.CurrentCount);
        Assert.False(releaser3Task.IsCompleted);

        // Now have the first user exit the semaphore and verify that the 3rd user gets in.
        releaser1.Dispose();
        await releaser3Task.WithCancellation(this.TimeoutToken);
    }
Exemple #3
0
        public async Task CurrentCount()
        {
            const int initialCapacity = 3;
            var       sem             = new AsyncSemaphore(initialCapacity);

            Assert.Equal(initialCapacity, sem.CurrentCount);

            var releasers = new AsyncSemaphore.Releaser[initialCapacity];

            for (int i = 0; i < initialCapacity; i++)
            {
                releasers[i] = await sem.EnterAsync();

                Assert.Equal(initialCapacity - (i + 1), sem.CurrentCount);
            }

            // After requesting another beyond its capacity, it should still report 0.
            var extraReleaser = sem.EnterAsync();

            Assert.Equal(0, sem.CurrentCount);

            for (int i = 0; i < initialCapacity; i++)
            {
                releasers[i].Dispose();
                Assert.Equal(i, sem.CurrentCount);
            }

            extraReleaser.Result.Dispose();
            Assert.Equal(initialCapacity, sem.CurrentCount);
        }
Exemple #4
0
    public async Task NoLeakForContestedRequests_ThatAreEventuallyAdmitted(int contestingNumbers)
    {
        var sem       = new AsyncSemaphore(1);
        var releasers = new Task <AsyncSemaphore.Releaser> [contestingNumbers];

        await this.CheckGCPressureAsync(
            async delegate
        {
            AsyncSemaphore.Releaser blockingReleaser = await sem.EnterAsync();
            for (int i = 0; i < releasers.Length; i++)
            {
                releasers[i] = sem.EnterAsync();
            }

            // Now let the first one in.
            blockingReleaser.Dispose();

            // Now dispose the first one, and each one afterward as it is let in.
            for (int i = 0; i < releasers.Length; i++)
            {
                (await releasers[i]).Dispose();
            }
        },
            maxBytesAllocated : -1,
            iterations : 5);
    }
Exemple #5
0
    public async Task TooManyReleases_SameStruct()
    {
        AsyncSemaphore.Releaser releaser = await this.lck.EnterAsync();

        releaser.Dispose();
        releaser.Dispose();
        Assert.Equal(2, this.lck.CurrentCount);
    }
Exemple #6
0
    public async Task TooManyReleases_CopyOfStruct_OverInitialCount()
    {
        AsyncSemaphore.Releaser releaser = await this.lck.EnterAsync();

        AsyncSemaphore.Releaser releaserCopy = releaser;

        releaser.Dispose();
        Assert.Equal(1, this.lck.CurrentCount);
        releaserCopy.Dispose();
        Assert.Equal(2, this.lck.CurrentCount);
    }
Exemple #7
0
    public async Task SemaphoreAwaitersAreQueued()
    {
        AsyncSemaphore.Releaser holder = await this.lck.EnterAsync();

        const int waiterCount = 5;
        var       cts         = new CancellationTokenSource[waiterCount];
        var       waiters     = new Task <AsyncSemaphore.Releaser> [waiterCount];

        for (int i = 0; i < waiterCount; i++)
        {
            cts[i]     = new CancellationTokenSource();
            waiters[i] = this.lck.EnterAsync(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);

        for (int i = 0; i < waiterCount; i++)
        {
            Assert.Equal(i == canceledWaiterIndex, waiters[i].IsCompleted);
        }

        holder.Dispose();
        for (int i = 0; i < waiterCount; i++)
        {
            if (i == canceledWaiterIndex)
            {
                continue;
            }

            // Assert that all subsequent waiters have not yet entered the semaphore.
            Assert.All(waiters.Skip(i + 1), w => Assert.True(w == waiters[canceledWaiterIndex] || !w.IsCompleted));

            // Now accept and exit the semaphore.
            using (await waiters[i].WithCancellation(this.TimeoutToken))
            {
                // We got the semaphore and will release it.
            }
        }
    }
Exemple #8
0
        public async Task NoLeakForUncontestedRequests(int initialCapacity)
        {
            var sem       = new AsyncSemaphore(initialCapacity);
            var releasers = new AsyncSemaphore.Releaser[initialCapacity];

            await this.CheckGCPressureAsync(
                async delegate
            {
                for (int i = 0; i < releasers.Length; i++)
                {
                    releasers[i] = await sem.EnterAsync();
                }

                for (int i = 0; i < releasers.Length; i++)
                {
                    releasers[i].Dispose();
                }
            },
                maxBytesAllocated : -1,
                iterations : 5);
        }
Exemple #9
0
    public async Task TooManyReleases_CopyOfStruct()
    {
        var sem = new AsyncSemaphore(2);

        AsyncSemaphore.Releaser releaser1 = await sem.EnterAsync();

        AsyncSemaphore.Releaser releaser2 = await sem.EnterAsync();

        // Assigning the releaser struct to another local variable copies it.
        AsyncSemaphore.Releaser releaser2Copy = releaser2;

        // Dispose of each copy of the releaser.
        // The double-release is undetectable. The semaphore should be back at capacity 2.
        releaser2.Dispose();
        Assert.Equal(1, sem.CurrentCount);
        releaser2Copy.Dispose();
        Assert.Equal(2, sem.CurrentCount);

        releaser1.Dispose();
        Assert.Equal(3, sem.CurrentCount);
    }