Exemple #1
0
        static void Main(string[] args)
        {
            var buffer = new BufferBlock <int>();

            buffer.Post(1);
            buffer.Post(2);
            buffer.Post(3);

            Console.WriteLine("buffer: " + buffer.Receive());
            Console.WriteLine("buffer: " + buffer.Receive());
            Console.WriteLine("buffer: " + buffer.Receive());

            var broadcast = new BroadcastBlock <int>(i => i);

            broadcast.Post(1);

            Console.WriteLine("broadcast: " + broadcast.Receive());
            Console.WriteLine("broadcast: " + broadcast.Receive());
            Console.WriteLine("broadcast: " + broadcast.Receive());


            var writeOnce = new WriteOnceBlock <int>(i => i);

            writeOnce.Post(1);
            writeOnce.Post(2);
            writeOnce.Post(3);

            Console.WriteLine("write-once: " + writeOnce.Receive());
        }
        private void LastMessageDublicate_ThrowTimeout()
        {
            var        nmsProtocol = _stack.GetCodec <NmsCodec>().Protocol;
            var        options     = new NibusOptions();
            NmsMessage lastMessage;

            nmsProtocol.IncomingMessages.TryReceive(null, out lastMessage);
            var query = new NmsRead(Destanation, 2);

            nmsProtocol.OutgoingMessages.Post(query);
            var        wob = new WriteOnceBlock <NmsMessage>(m => m);
            NmsMessage response, response2;

            using (nmsProtocol.IncomingMessages.LinkTo(
                       wob, m => !ReferenceEquals(m, lastMessage) && m.IsResponse && m.ServiceType == query.ServiceType && m.Id == query.Id))
            {
                response = wob.Receive(options.Timeout);
            }
            nmsProtocol.IncomingMessages.TryReceive(null, out lastMessage);
            Assert.That(lastMessage, Is.EqualTo(response));
            var wob2 = new WriteOnceBlock <NmsMessage>(m => m);

            using (nmsProtocol.IncomingMessages.LinkTo(
                       wob2, m => !ReferenceEquals(m, lastMessage) && m.IsResponse && m.ServiceType == query.ServiceType && m.Id == query.Id))
            {
                response2 = wob2.Receive(options.Timeout);
            }
        }
Exemple #3
0
        public void Run()
        {
            // Example 1:
            // ____________________________________________
            // Create a WriteOnceBlock<string> object.
            var writeOnceBlock = new WriteOnceBlock <string>(null);

            // Post several messages to the block in parallel. The first
            // message to be received is written to the block.
            // Subsequent messages are discarded.
            Parallel.Invoke(
                () => writeOnceBlock.Post("Message 1"),
                () => writeOnceBlock.Post("Message 2"),
                () => writeOnceBlock.Post("Message 3"));

            // Receive the message from the block.
            Console.WriteLine(writeOnceBlock.Receive());

            /* Sample output:
             * Message 2
             */

            // Example 2
            // ________________________________________________
            // Create a shared CancellationTokenSource object to enable the
            // TrySolution method to be cancelled.
            var cts = new CancellationTokenSource();

            // Create three TransformBlock<int, int> objects.
            // Each TransformBlock<int, int> object calls the TrySolution method.
            Func <int, int> action       = n => TrySolution(n, cts.Token);
            var             trySolution1 = new TransformBlock <int, int>(action);
            var             trySolution2 = new TransformBlock <int, int>(action);
            var             trySolution3 = new TransformBlock <int, int>(action);

            // Post data to each TransformBlock<int, int> object.
            trySolution1.Post(11);
            trySolution2.Post(21);
            trySolution3.Post(31);

            // Call the ReceiveFromAny<T> method to receive the result from the
            // first TransformBlock<int, int> object to finish.
            int result = ReceiveFromAny(trySolution1, trySolution2, trySolution3);

            // Cancel all calls to TrySolution that are still active.
            cts.Cancel();

            // Print the result to the console.
            Console.WriteLine("The solution is {0}.", result);

            cts.Dispose();

            /* Sample output:
             * The solution is 53.
             */
        }
Exemple #4
0
        public static T RecieveFromAny <T>(params ISourceBlock <T>[] sources)
        {
            var writeOnceBlock = new WriteOnceBlock <T>(e => e);

            foreach (var source in sources)
            {
                source.LinkTo(writeOnceBlock, new DataflowLinkOptions {
                    MaxMessages = 1
                });
            }
            return(writeOnceBlock.Receive());
        }
        public override void Run()
        {
            WriteOnceBlock <RunModel> writeOnceBlock = new WriteOnceBlock <RunModel>((model) => model);

            var models = this.CreateCollection();

            Parallel.ForEach(models, model => writeOnceBlock.Post(model));

            // WriteOnceBlock 只会保留第一个结果,且不限读取次数
            Parallel.For(0, 10, (index) =>
            {
                var model = writeOnceBlock.Receive();
                Helper.PrintLine($"{index} {model.Name}");
            });
        }
Exemple #6
0
        public async Task TestReceiveThenPost()
        {
            var wob     = new WriteOnceBlock <int>(null);
            var ignored = Task.Run(() => wob.Post(42));

            Assert.Equal(expected: 42, actual: wob.Receive()); // this should always pass, but due to race we may not test what we're hoping to
            await wob.Completion;

            wob = new WriteOnceBlock <int>(null);
            Task <int> t = wob.ReceiveAsync();

            Assert.False(t.IsCompleted);
            wob.Post(16);
            Assert.Equal(expected: 16, actual: await t);
        }
Exemple #7
0
        static public void Run()
        {
            var woBlock = new WriteOnceBlock <int>(n => n);

            for (int i = 0; i < 10; i++)
            {
                woBlock.Post(i);
            }

            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(woBlock.Receive());
            }

            Console.WriteLine("Done");
        }
Exemple #8
0
        private static void DataStructure_WriteOnceBlock()
        {
            // Create a WriteOnceBlock<string> object.
            var writeOnceBlock = new WriteOnceBlock <string>(null);

            // Post several messages to the block in parallel. The first
            // message to be received is written to the block.
            // Subsequent messages are discarded.
            Parallel.Invoke(
                () => writeOnceBlock.Post("Message 1"),
                () => writeOnceBlock.Post("Message 2"),
                () => writeOnceBlock.Post("Message 3"));

            // Receive the message from the block.
            Console.WriteLine(writeOnceBlock.Receive());
        }
Exemple #9
0
        // Receives the value from the first provided source that has
        // a message.
        public static T ReceiveFromAny <T>(params ISourceBlock <T>[] sources)
        {
            // Create a WriteOnceBlock<T> object and link it to each source block.
            var writeOnceBlock = new WriteOnceBlock <T>(e => e);

            foreach (var source in sources)
            {
                // Setting MaxMessages to one instructs
                // the source block to unlink from the WriteOnceBlock<T> object
                // after offering the WriteOnceBlock<T> object one message.
                source.LinkTo(writeOnceBlock, new DataflowLinkOptions {
                    MaxMessages = 1
                });
            }
            // Return the first value that is offered to the WriteOnceBlock object.
            return(writeOnceBlock.Receive());
        }
Exemple #10
0
        private static void TestSync4()
        {
            wb.LinkTo(displayBlock);
            wb.LinkTo(saveBlock);
            wb.LinkTo(sendBlock);

            for (int i = 0; i < 4; i++)
            {
                wb.Post(i);
            }

            wb.Complete();
            Console.WriteLine("Post Finished");
            wb.Completion.Wait();
            Console.WriteLine("Process Finished");
            Console.WriteLine("Recive:" + wb.Receive());
        }
        public void start()
        {
            var block = new WriteOnceBlock <int>(x => x);

            for (int i = 0; i < 10; i++)
            {
                if (!block.Post(i))
                {
                    Console.WriteLine($"Failed Post - {i}");
                }
            }
            for (int i = 0; i < 10; i++)
            {
                var x = block.Receive();

                Console.WriteLine($"Received - {x}");
            }
        }
Exemple #12
0
        public void TestLink()
        {
            var transformBlock = new TransformWithoutBufferBlock <int, int>(x => x);

            var target1 = new WriteOnceBlock <int>(null);
            var target2 = new WriteOnceBlock <int>(null);
            var target3 = new WriteOnceBlock <int>(null);

            transformBlock.LinkTo(target1);
            transformBlock.LinkTo(target2, x => x != 2);
            transformBlock.LinkTo(target3);

            transformBlock.Post(1).IsTrue();
            transformBlock.Post(2).IsTrue();
            transformBlock.Post(3).IsTrue();

            target1.Receive(TestUtils.SometimeSoon).Is(1);
            target2.Receive(TestUtils.SometimeSoon).Is(3);
            target3.Receive(TestUtils.SometimeSoon).Is(2);
        }
Exemple #13
0
        public void TestWriteOnceCloning()
        {
            // Test cloning when a clone function is provided
            {
                var writeOnce = new WriteOnceBlock <int>(x => - x);
                Assert.True(writeOnce.Post(42), "Expected initial post on cloning WriteOnce to succeed");
                Assert.False(writeOnce.Post(43), "Expected secondary post on cloning WriteOnce to fail");
                Assert.True(writeOnce.Receive() == -42, "Expected Receive'd data to be a clone");
                int item;
                Assert.True(writeOnce.TryReceive(out item) && item == -42, "Expected TryReceive'd data to be a clone");
                IList <int> items;
                Assert.True(((IReceivableSourceBlock <int>)writeOnce).TryReceiveAll(out items) && items.Count == 1 && items[0] == -42, "Expected TryReceiveAll'd data to be a clone");
                var ab = new ActionBlock <int>(i =>
                {
                    Assert.True(i == -42, "Expected propagated data to be a clone.");
                });
                writeOnce.LinkTo(ab);
                ab.Complete();
                Assert.True(ab.Completion.Wait(4000), "Expected action block to complete after cloned data flowed to it");
            }

            // Test successful processing when no clone function exists
            {
                var data      = new object();
                var writeOnce = new WriteOnceBlock <object>(null);
                Assert.True(writeOnce.Post(data), "Expected initial post on non-cloning WriteOnce to succeed");
                Assert.False(writeOnce.Post(new object()), "Expected secondary post on non-cloning WriteOnce to fail");
                Assert.True(writeOnce.Receive() == data, "Expected Receive'd data to be original data");
                object item;
                Assert.True(writeOnce.TryReceive(out item) && item == data, "Expected TryReceive'd data to be original data");
                IList <object> items;
                Assert.True(((IReceivableSourceBlock <object>)writeOnce).TryReceiveAll(out items) && items.Count == 1 && items[0] == data, "Expected TryReceiveAll'd data to be original data");
                var ab = new ActionBlock <object>(i =>
                {
                    Assert.True(i == data, "Expected propagated data to be original data.");
                });
                writeOnce.LinkTo(ab);
                ab.Complete();
                Assert.True(ab.Completion.Wait(4000), "Expected action block to complete after original data flowed to it");
            }
        }
Exemple #14
0
        public static void Run()
        {
            // Create a WriteOnceBlock<string> object.
            // Provides a buffer for receiving and storing at most one element in a network of dataflow blocks
            WriteOnceBlock <string> writeOnceBlock = new WriteOnceBlock <string>(null);

            // Post several messages to the block in parallel.
            // The first message to be received is written to the block.
            // Subsequent messages are discarded.
            // Executes each of the provided actions, possibly in parallel
            Parallel.Invoke(
                () => writeOnceBlock.Post("Message 1. ThreadId: " + Thread.CurrentThread.ManagedThreadId),
                () => writeOnceBlock.Post("Message 2. ThreadId: " + Thread.CurrentThread.ManagedThreadId),
                () => writeOnceBlock.Post("Message 3. ThreadId: " + Thread.CurrentThread.ManagedThreadId));

            // Receive the message from the block.
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(writeOnceBlock.Receive());
            }
        }
Exemple #15
0
        static void ShowWriteOnceBlock()
        {
            // <snippet3>
            // Create a WriteOnceBlock<string> object.
            var writeOnceBlock = new WriteOnceBlock <string>(null);

            // Post several messages to the block in parallel. The first
            // message to be received is written to the block.
            // Subsequent messages are discarded.
            Parallel.Invoke(
                () => writeOnceBlock.Post("Message 1"),
                () => writeOnceBlock.Post("Message 2"),
                () => writeOnceBlock.Post("Message 3"));

            // Receive the message from the block.
            Console.WriteLine(writeOnceBlock.Receive());

            /* Sample output:
             * Message 2
             */
            // </snippet3>
        }
Exemple #16
0
        public async void TestLink()
        {
            var testBlock = new FilterBlock <int>(x => x % 2 != 0);

            var target1 = new WriteOnceBlock <int>(null);
            var target2 = new WriteOnceBlock <int>(null);
            var target3 = new WriteOnceBlock <int>(null);

            testBlock.LinkTo(target1);
            testBlock.LinkTo(target2, x => x != 3);
            testBlock.LinkTo(target3);

            testBlock.Post(1).IsTrue();
            (await testBlock.SendAsync(2).CompleteSoon()).IsTrue(); // drop
            (await testBlock.SendAsync(3).CompleteSoon()).IsTrue();
            (await testBlock.SendAsync(4).CompleteSoon()).IsTrue(); // drop
            (await testBlock.SendAsync(5).CompleteSoon()).IsTrue();

            target1.Receive(TestUtils.SometimeSoon).Is(1);
            target2.Receive(TestUtils.SometimeSoon).Is(5);
            target3.Receive(TestUtils.SometimeSoon).Is(3);
        }
        // Demonstrates how to unlink dataflow blocks.
        // Receives the value from the first provided source that has
        // a message.
        /*ISourceBlock<TOutput> Interface Represents a dataflow block that is a source of data*/
        public static T ReceiveFromAny <T>(params ISourceBlock <T>[] sources)
        {
            // Create a WriteOnceBlock<T> object and link it to each source block.

            /*Provides a buffer for receiving and storing at most one element
             * in a network of dataflow blocks*/
            WriteOnceBlock <T> writeOnceBlock = new WriteOnceBlock <T>(e => e);

            foreach (ISourceBlock <T> source in sources)
            {
                // Setting MaxMessages to one instructs
                // the source block to unlink from the WriteOnceBlock<T> object
                // after offering the WriteOnceBlock<T> object one message.
                source.LinkTo(writeOnceBlock, new DataflowLinkOptions
                {
                    MaxMessages = 1
                });
            }
            // Return the first value that is offered to the WriteOnceBlock object.
            T receive = writeOnceBlock.Receive();

            return(receive);
        }
Exemple #18
0
        public void RunWriteOnceBlockConformanceTests()
        {
            bool passed = true, localPassed = true;

            {
                // Test posting then receiving
                localPassed = true;
                var wob             = new WriteOnceBlock <int>(i => i);
                int successfulPosts = 0;
                for (int i = 10; i <= 20; i++)
                {
                    successfulPosts += wob.Post(i) ? 1 : 0;
                }
                localPassed |= successfulPosts == 1;
                localPassed |= wob.Receive() == 10;
                Console.WriteLine("{0}: Posting then receiving", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test receiving then posting
                localPassed = true;
                var wob = new WriteOnceBlock <int>(i => i);
                Task.Factory.StartNew(() =>
                {
                    Task.Delay(1000).Wait();
                    wob.Post(42);
                });
                localPassed |= wob.Receive() == 42;
                localPassed |= wob.Post(43) == false;
                wob.Completion.Wait();
                Console.WriteLine("{0}: Receiving then posting", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test broadcasting
                localPassed = true;
                var wob = new WriteOnceBlock <int>(i => i + 1);
                var tb1 = new TransformBlock <int, int>(i => i);
                var tb2 = new TransformBlock <int, int>(i => i);
                var tb3 = new TransformBlock <int, int>(i => i);
                wob.LinkTo(tb1);
                wob.LinkTo(tb2);
                wob.LinkTo(tb3);
                wob.Post(42);
                localPassed |= tb1.Receive() == 43;
                localPassed |= tb2.Receive() == 43;
                localPassed |= tb3.Receive() == 43;
                Console.WriteLine("{0}: Broadcasting", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test using a precanceled token
                localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    cts.Cancel();
                    var dbo = new DataflowBlockOptions {
                        CancellationToken = cts.Token
                    };
                    var wob = new WriteOnceBlock <int>(i => i, dbo);

                    int         ignoredValue;
                    IList <int> ignoredValues;
                    localPassed &= wob.LinkTo(new ActionBlock <int>(delegate { })) != null;
                    localPassed &= wob.SendAsync(42).Result == false;
                    localPassed &= ((IReceivableSourceBlock <int>)wob).TryReceiveAll(out ignoredValues) == false;
                    localPassed &= wob.Post(42) == false;
                    localPassed &= wob.TryReceive(out ignoredValue) == false;
                    localPassed &= wob.Completion != null;
                    wob.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }
                Console.WriteLine("{0}: Precanceled tokens work correctly", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test using token canceled after construction
                localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    var dbo = new DataflowBlockOptions {
                        CancellationToken = cts.Token
                    };
                    var wob = new WriteOnceBlock <int>(i => i, dbo);
                    cts.Cancel();

                    int         ignoredValue;
                    IList <int> ignoredValues;
                    localPassed &= wob.LinkTo(new ActionBlock <int>(delegate { })) != null;
                    localPassed &= wob.SendAsync(42).Result == false;
                    localPassed &= ((IReceivableSourceBlock <int>)wob).TryReceiveAll(out ignoredValues) == false;
                    localPassed &= wob.Post(42) == false;
                    localPassed &= wob.TryReceive(out ignoredValue) == false;
                    localPassed &= wob.Completion != null;
                    wob.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }
                Console.WriteLine("{0}: Precanceled tokens work correctly", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            Assert.True(passed, "Test failed.");
        }
Exemple #19
0
        public async Task TestCloning()
        {
            // Test cloning when a clone function is provided
            {
                int data = 42;
                var wob  = new WriteOnceBlock <int>(x => - x);
                Assert.True(wob.Post(data));

                Assert.False(wob.Post(data + 1));

                for (int i = 0; i < 3; i++)
                {
                    int item;
                    Assert.True(wob.TryReceive(out item));
                    Assert.Equal(expected: -data, actual: item);

                    Assert.Equal(expected: -data, actual: wob.Receive());

                    Assert.Equal(expected: -data, actual: await wob.ReceiveAsync());

                    IList <int> items;
                    Assert.True(((IReceivableSourceBlock <int>)wob).TryReceiveAll(out items));
                    Assert.Equal(expected: items.Count, actual: 1);
                    Assert.Equal(expected: -data, actual: items[0]);
                }

                int result = 0;
                var target = new ActionBlock <int>(i => {
                    Assert.Equal(expected: 0, actual: result);
                    result = i;
                    Assert.Equal(expected: -data, actual: i);
                });
                wob.LinkTo(target, new DataflowLinkOptions {
                    PropagateCompletion = true
                });
                await target.Completion;
            }

            // Test successful processing when no clone function exists
            {
                var data = new object();
                var wob  = new WriteOnceBlock <object>(null);
                Assert.True(wob.Post(data));

                Assert.False(wob.Post(new object()));

                object result;
                for (int i = 0; i < 3; i++)
                {
                    Assert.True(wob.TryReceive(out result));
                    Assert.Equal(expected: data, actual: result);

                    Assert.Equal(expected: data, actual: wob.Receive());
                    Assert.Equal(expected: data, actual: await wob.ReceiveAsync());

                    IList <object> items;
                    Assert.True(((IReceivableSourceBlock <object>)wob).TryReceiveAll(out items));
                    Assert.Equal(expected: 1, actual: items.Count);
                    Assert.Equal(expected: data, actual: items[0]);
                }

                result = null;
                var target = new ActionBlock <object>(o => {
                    Assert.Null(result);
                    result = o;
                    Assert.Equal(expected: data, actual: o);
                });
                wob.LinkTo(target, new DataflowLinkOptions {
                    PropagateCompletion = true
                });
                await target.Completion;
            }
        }
        public void RunWriteOnceBlockConformanceTests()
        {
            bool passed = true, localPassed = true;
            {
                // Test posting then receiving
                localPassed = true;
                var wob = new WriteOnceBlock<int>(i => i);
                int successfulPosts = 0;
                for (int i = 10; i <= 20; i++)
                {
                    successfulPosts += wob.Post(i) ? 1 : 0;
                }
                localPassed |= successfulPosts == 1;
                localPassed |= wob.Receive() == 10;
                Console.WriteLine("{0}: Posting then receiving", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test receiving then posting
                localPassed = true;
                var wob = new WriteOnceBlock<int>(i => i);
                Task.Factory.StartNew(() =>
                {
                    Task.Delay(1000).Wait();
                    wob.Post(42);
                });
                localPassed |= wob.Receive() == 42;
                localPassed |= wob.Post(43) == false;
                wob.Completion.Wait();
                Console.WriteLine("{0}: Receiving then posting", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test broadcasting
                localPassed = true;
                var wob = new WriteOnceBlock<int>(i => i + 1);
                var tb1 = new TransformBlock<int, int>(i => i);
                var tb2 = new TransformBlock<int, int>(i => i);
                var tb3 = new TransformBlock<int, int>(i => i);
                wob.LinkTo(tb1);
                wob.LinkTo(tb2);
                wob.LinkTo(tb3);
                wob.Post(42);
                localPassed |= tb1.Receive() == 43;
                localPassed |= tb2.Receive() == 43;
                localPassed |= tb3.Receive() == 43;
                Console.WriteLine("{0}: Broadcasting", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test using a precanceled token
                localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    cts.Cancel();
                    var dbo = new DataflowBlockOptions { CancellationToken = cts.Token };
                    var wob = new WriteOnceBlock<int>(i => i, dbo);

                    int ignoredValue;
                    IList<int> ignoredValues;
                    localPassed &= wob.LinkTo(new ActionBlock<int>(delegate { })) != null;
                    localPassed &= wob.SendAsync(42).Result == false;
                    localPassed &= ((IReceivableSourceBlock<int>)wob).TryReceiveAll(out ignoredValues) == false;
                    localPassed &= wob.Post(42) == false;
                    localPassed &= wob.TryReceive(out ignoredValue) == false;
                    localPassed &= wob.Completion != null;
                    wob.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }
                Console.WriteLine("{0}: Precanceled tokens work correctly", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            {
                // Test using token canceled after construction
                localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    var dbo = new DataflowBlockOptions { CancellationToken = cts.Token };
                    var wob = new WriteOnceBlock<int>(i => i, dbo);
                    cts.Cancel();

                    int ignoredValue;
                    IList<int> ignoredValues;
                    localPassed &= wob.LinkTo(new ActionBlock<int>(delegate { })) != null;
                    localPassed &= wob.SendAsync(42).Result == false;
                    localPassed &= ((IReceivableSourceBlock<int>)wob).TryReceiveAll(out ignoredValues) == false;
                    localPassed &= wob.Post(42) == false;
                    localPassed &= wob.TryReceive(out ignoredValue) == false;
                    localPassed &= wob.Completion != null;
                    wob.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }
                Console.WriteLine("{0}: Precanceled tokens work correctly", localPassed ? "Success" : "Failure");
                passed &= localPassed;
            }

            Assert.True(passed, "Test failed.");
        }
        public void TestWriteOnceCloning()
        {
            // Test cloning when a clone function is provided
            {
                var writeOnce = new WriteOnceBlock<int>(x => -x);
                Assert.True(writeOnce.Post(42), "Expected initial post on cloning WriteOnce to succeed");
                Assert.False(writeOnce.Post(43), "Expected secondary post on cloning WriteOnce to fail");
                Assert.True(writeOnce.Receive() == -42, "Expected Receive'd data to be a clone");
                int item;
                Assert.True(writeOnce.TryReceive(out item) && item == -42, "Expected TryReceive'd data to be a clone");
                IList<int> items;
                Assert.True(((IReceivableSourceBlock<int>)writeOnce).TryReceiveAll(out items) && items.Count == 1 && items[0] == -42, "Expected TryReceiveAll'd data to be a clone");
                var ab = new ActionBlock<int>(i =>
                {
                    Assert.True(i == -42, "Expected propagated data to be a clone.");
                });
                writeOnce.LinkTo(ab);
                ab.Complete();
                Assert.True(ab.Completion.Wait(4000), "Expected action block to complete after cloned data flowed to it");
            }

            // Test successful processing when no clone function exists
            {
                var data = new object();
                var writeOnce = new WriteOnceBlock<object>(null);
                Assert.True(writeOnce.Post(data), "Expected initial post on non-cloning WriteOnce to succeed");
                Assert.False(writeOnce.Post(new object()), "Expected secondary post on non-cloning WriteOnce to fail");
                Assert.True(writeOnce.Receive() == data, "Expected Receive'd data to be original data");
                object item;
                Assert.True(writeOnce.TryReceive(out item) && item == data, "Expected TryReceive'd data to be original data");
                IList<object> items;
                Assert.True(((IReceivableSourceBlock<object>)writeOnce).TryReceiveAll(out items) && items.Count == 1 && items[0] == data, "Expected TryReceiveAll'd data to be original data");
                var ab = new ActionBlock<object>(i =>
                {
                    Assert.True(i == data, "Expected propagated data to be original data.");
                });
                writeOnce.LinkTo(ab);
                ab.Complete();
                Assert.True(ab.Completion.Wait(4000), "Expected action block to complete after original data flowed to it");
            }
        }
        public async Task TestReceiveThenPost()
        {
            var wob = new WriteOnceBlock<int>(null);
            var ignored = Task.Run(() => wob.Post(42));
            Assert.Equal(expected: 42, actual: wob.Receive()); // this should always pass, but due to race we may not test what we're hoping to
            await wob.Completion;

            wob = new WriteOnceBlock<int>(null);
            Task<int> t = wob.ReceiveAsync();
            Assert.False(t.IsCompleted);
            wob.Post(16);
            Assert.Equal(expected: 16, actual: await t);
        }
        public async Task TestCloning()
        {
            // Test cloning when a clone function is provided
            {
                int data = 42;
                var wob = new WriteOnceBlock<int>(x => -x);
                Assert.True(wob.Post(data));

                Assert.False(wob.Post(data + 1));

                for (int i = 0; i < 3; i++)
                {
                    int item;
                    Assert.True(wob.TryReceive(out item));
                    Assert.Equal(expected: -data, actual: item);

                    Assert.Equal(expected: -data, actual: wob.Receive());

                    Assert.Equal(expected: -data, actual: await wob.ReceiveAsync());

                    IList<int> items;
                    Assert.True(((IReceivableSourceBlock<int>)wob).TryReceiveAll(out items));
                    Assert.Equal(expected: items.Count, actual: 1);
                    Assert.Equal(expected: -data, actual: items[0]);
                }

                int result = 0;
                var target = new ActionBlock<int>(i => {
                    Assert.Equal(expected: 0, actual: result);
                    result = i;
                    Assert.Equal(expected: -data, actual: i);
                });
                wob.LinkTo(target, new DataflowLinkOptions { PropagateCompletion = true });
                await target.Completion;
            }

            // Test successful processing when no clone function exists
            {
                var data = new object();
                var wob = new WriteOnceBlock<object>(null);
                Assert.True(wob.Post(data));

                Assert.False(wob.Post(new object()));

                object result;
                for (int i = 0; i < 3; i++)
                {
                    Assert.True(wob.TryReceive(out result));
                    Assert.Equal(expected: data, actual: result);

                    Assert.Equal(expected: data, actual: wob.Receive());
                    Assert.Equal(expected: data, actual: await wob.ReceiveAsync());

                    IList<object> items;
                    Assert.True(((IReceivableSourceBlock<object>)wob).TryReceiveAll(out items));
                    Assert.Equal(expected: 1, actual: items.Count);
                    Assert.Equal(expected: data, actual: items[0]);
                }

                result = null;
                var target = new ActionBlock<object>(o => {
                    Assert.Null(result);
                    result = o;
                    Assert.Equal(expected: data, actual: o);
                });
                wob.LinkTo(target, new DataflowLinkOptions { PropagateCompletion = true });
                await target.Completion;
            }
        }