Example #1
0
        public void OperationTracker_Basics1()
        {
            var o = new OperationTracker();

            //
            // Enter a few times.
            //

            var g1 = o.Enter();
            var g2 = o.Enter();

            //
            // Double-dispose is fine.
            //

            g1.Dispose();
            g1.Dispose();

            //
            // Initiate dispose.
            //

            var d = o.DisposeAsync()
#if NET5_0 || NETCOREAPP3_1
                    .AsTask()
#endif
            ;

            Assert.IsFalse(d.IsCompleted);

            //
            // Cannot enter again.
            //

            Assert.ThrowsException <ObjectDisposedException>(() => o.Enter());

            //
            // Exit the last operation.
            //

            g2.Dispose();

            //
            // Tracker is disposed now.
            //

            d.Wait();

            //
            // Cannot enter again.
            //

            Assert.ThrowsException <ObjectDisposedException>(() => o.Enter());
        }
Example #2
0
        public void OperationTracker_Basics2()
        {
            var o = new OperationTracker();

            //
            // Enter a few times.
            //

            var g1 = o.Enter();
            var g2 = o.Enter();

            //
            // Initiate dispose a first time.
            //

            var d1 = o.DisposeAsync()
#if NET5_0 || NETCOREAPP3_1
                     .AsTask()
#endif
            ;

            Assert.IsFalse(d1.IsCompleted);

            //
            // Cannot enter again.
            //

            Assert.ThrowsException <ObjectDisposedException>(() => o.Enter());

            //
            // Initiate dispose a second time.
            //

            var d2 = o.DisposeAsync()
#if NET5_0 || NETCOREAPP3_1
                     .AsTask()
#endif
            ;

            Assert.IsFalse(d2.IsCompleted);

            //
            // Exit one of the operations.
            //

            g2.Dispose();

            Assert.IsFalse(d1.IsCompleted);
            Assert.IsFalse(d2.IsCompleted);

            //
            // Cannot enter again.
            //

            Assert.ThrowsException <ObjectDisposedException>(() => o.Enter());

            //
            // Exit the other operation.
            //

            g1.Dispose();

            //
            // Tracker is disposed now.
            //

            d1.Wait();
            d2.Wait();

            //
            // Cannot enter again.
            //

            Assert.ThrowsException <ObjectDisposedException>(() => o.Enter());

            //
            // Dispose is a no-op now.
            //

            o.DisposeAsync()
#if NET5_0 || NETCOREAPP3_1
            .AsTask()
#endif
            .Wait();

            //
            // Cannot enter again.
            //

            Assert.ThrowsException <ObjectDisposedException>(() => o.Enter());
        }
Example #3
0
        public void OperationTracker_Concurrent()
        {
            //
            // Create enough competing threads so we have concurrency the moment we dispose the tracker.
            //

            int n = Environment.ProcessorCount * 4;

            using var c = new CountdownEvent(n);
            using var e = new ManualResetEvent(initialState: false);

            var tasks = new Thread[n];

            var t = new OperationTracker();

            //
            // Each thread will enter, then signal having arrived within the tracked scope, and then wait for a signal to continue.
            //

            for (int i = 0; i < n; i++)
            {
                var u = new Thread(() =>
                {
                    using var _ = t.Enter();

                    c.Signal();
                    e.WaitOne();

                    Thread.Yield();
                });

                tasks[i] = u;

                u.Start();
            }

            //
            // Wait for all threads to arrive, then let them loose.
            //

            c.Wait();
            e.Set();

            //
            // Initiate and await completion of closing the tracker.
            //

            t.DisposeAsync()
#if NET5_0 || NETCOREAPP3_1
            .AsTask()
#endif
            .Wait();

            //
            // Join all threads.
            //

            foreach (var u in tasks)
            {
                u.Join();
            }
        }