Search code examples
c#tpl-dataflow

Does linking keep the linked block alive?


When using System.Threading.Tasks.Dataflow, if I link block a to block b, will the link keep b alive? Or do I need to keep a reference to b around to prevent it from being collected?

internal class SomeDataflowUser
{
    public SomeDataflowUser()
    { 
        _a = new SomeBlock();
        var b = new SomeOtherBlock();
        _a.LinkTo(b);
    }

    public void ReactToIncomingMessage( Something data )
    {    
        // might b be collected here?
        _a.Post( data );
    }

    private ISourceBlock<Something> _a;
}

Solution

  • In addition to @Eric great explanation of GC behavior I want to address the special case related to TPL-Dataflow. You can easily see the behavior that LinkTo yields from a simple test. Notice that nothing, to my knowledge, is holding on to b except for its link to a.

    [TestFixture]
    public class BlockTester
    {
    
        private int count;
    
        [Test]
        public async Task Test()
        {
            var inputBlock = BuildPipeline();
            var max = 1000;
            foreach (var input in Enumerable.Range(1, max))
            {
                inputBlock.Post(input);
            }
            inputBlock.Complete();
    
            //No reference to block b
            //so we can't await b completion
            //instead we'll just wait a second since
            //the block should finish nearly immediately
            await Task.Delay(TimeSpan.FromSeconds(1));
            Assert.AreEqual(max, count);
        }
    
        public ITargetBlock<int> BuildPipeline()
        {
            var a = new TransformBlock<int, int>(x => x);
            var b = new ActionBlock<int>(x => count = x);
            a.LinkTo(b, new DataflowLinkOptions() {PropagateCompletion = true});
            return a;
        }
    }