C#idiomatic C#
how-to-specify-a-task-scheduler-in-a-dataflow-blockstandard/parallel-programming

Async and concurrency

How to: Specify a Task Scheduler in a Dataflow Block

Learn more about: How to: Specify a Task Scheduler in a Dataflow Block

  • page standard/parallel-programming/how-to-specify-a-task-scheduler-in-a-dataflow-block
  • updated 03/30/2017

This document demonstrates how to associate a specific task scheduler when you use dataflow in your application. The example uses the System.Threading.Tasks.ConcurrentExclusiveSchedulerPair class in a Windows Forms application to show when reader tasks are active and when a writer task is active. It also uses the System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext method to enable a dataflow block to run on the user-interface thread.

To Create the Windows Forms Application

  1. Create a Visual C# or Visual Basic Windows Forms Application project. In the following steps, the project is named WriterReadersWinForms.

  2. On the form designer for the main form, Form1.cs (Form1.vb for Visual Basic), add four System.Windows.Forms.CheckBox controls. Set the System.Windows.Forms.Control.Text property to Reader 1 for checkBox1, Reader 2 for checkBox2, Reader 3 for checkBox3, and Writer for checkBox4. Set the System.Windows.Forms.Control.Enabled property for each control to False.

  3. Add a System.Windows.Forms.Timer control to the form. Set the System.Windows.Forms.Timer.Interval property to 2500.

Adding Dataflow Functionality

This section describes how to create the dataflow blocks that participate in the application and how to associate each one with a task scheduler.

To Add Dataflow Functionality to the Application

  1. In your project, add a reference to System.Threading.Tasks.Dataflow.dll.

  2. Ensure that Form1.cs (Form1.vb for Visual Basic) contains the following using directives (Imports in Visual Basic).

    sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/cs/writerreaderswinforms/form1.cs1

    csharp
    // <snippet100>
    // <snippet1>
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Windows.Forms;
    // </snippet1>
    
    namespace WriterReadersWinForms
    {
       public partial class Form1 : Form
       {
          // <snippet2>
          // Broadcasts values to an ActionBlock<int> object that is associated
          // with each check box.
          BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);
          // </snippet2>
    
          public Form1()
          {
             InitializeComponent();
    
             // <snippet3>
             // Create an ActionBlock<CheckBox> object that toggles the state
             // of CheckBox objects.
             // Specifying the current synchronization context enables the
             // action to run on the user-interface thread.
             var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
             {
                checkBox.Checked = !checkBox.Checked;
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
             });
             // </snippet3>
    
             // <snippet4>
             // Create a ConcurrentExclusiveSchedulerPair object.
             // Readers will run on the concurrent part of the scheduler pair.
             // The writer will run on the exclusive part of the scheduler pair.
             var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();
    
             // Create an ActionBlock<int> object for each reader CheckBox object.
             // Each ActionBlock<int> object represents an action that can read
             // from a resource in parallel to other readers.
             // Specifying the concurrent part of the scheduler pair enables the
             // reader to run in parallel to other actions that are managed by
             // that scheduler.
             var readerActions =
                from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
                select new ActionBlock<int>(milliseconds =>
                {
                   // Toggle the check box to the checked state.
                   toggleCheckBox.Post(checkBox);
    
                   // Perform the read action. For demonstration, suspend the current
                   // thread to simulate a lengthy read operation.
                   Thread.Sleep(milliseconds);
    
                   // Toggle the check box to the unchecked state.
                   toggleCheckBox.Post(checkBox);
                },
                new ExecutionDataflowBlockOptions
                {
                   TaskScheduler = taskSchedulerPair.ConcurrentScheduler
                });
    
             // Create an ActionBlock<int> object for the writer CheckBox object.
             // This ActionBlock<int> object represents an action that writes to
             // a resource, but cannot run in parallel to readers.
             // Specifying the exclusive part of the scheduler pair enables the
             // writer to run in exclusively with respect to other actions that are
             // managed by the scheduler pair.
             var writerAction = new ActionBlock<int>(milliseconds =>
             {
                // Toggle the check box to the checked state.
                toggleCheckBox.Post(checkBox4);
    
                // Perform the write action. For demonstration, suspend the current
                // thread to simulate a lengthy write operation.
                Thread.Sleep(milliseconds);
    
                // Toggle the check box to the unchecked state.
                toggleCheckBox.Post(checkBox4);
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = taskSchedulerPair.ExclusiveScheduler
             });
    
             // Link the broadcaster to each reader and writer block.
             // The BroadcastBlock<T> class propagates values that it
             // receives to all connected targets.
             foreach (var readerAction in readerActions)
             {
                broadcaster.LinkTo(readerAction);
             }
             broadcaster.LinkTo(writerAction);
             // </snippet4>
    
             // <snippet5>
             // Start the timer.
             timer1.Start();
             // </snippet5>
          }
    
          // <snippet6>
          // Event handler for the timer.
          private void timer1_Tick(object sender, EventArgs e)
          {
             // Post a value to the broadcaster. The broadcaster
             // sends this message to each target.
             broadcaster.Post(1000);
          }
          // </snippet6>
       }
    }
    // </snippet100>

    sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/vb/writerreaderswinforms/form1.vb1

    vb
    ' <snippet100>
    ' <snippet1>
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Threading.Tasks.Dataflow
    
    ' </snippet1>
    
    Namespace WriterReadersWinForms
        Partial Public Class Form1
            Inherits Form
            ' <snippet2>
            ' Broadcasts values to an ActionBlock<int> object that is associated
            ' with each check box.
            Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)
            ' </snippet2>
    
            Public Sub New()
                InitializeComponent()
    
                ' <snippet3>
                ' Create an ActionBlock<CheckBox> object that toggles the state
                ' of CheckBox objects.
                ' Specifying the current synchronization context enables the 
                ' action to run on the user-interface thread.
                Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
                ' </snippet3>
    
                ' <snippet4>
                ' Create a ConcurrentExclusiveSchedulerPair object.
                ' Readers will run on the concurrent part of the scheduler pair.
                ' The writer will run on the exclusive part of the scheduler pair.
                Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()
    
                ' Create an ActionBlock<int> object for each reader CheckBox object.
                ' Each ActionBlock<int> object represents an action that can read 
                ' from a resource in parallel to other readers.
                ' Specifying the concurrent part of the scheduler pair enables the 
                ' reader to run in parallel to other actions that are managed by 
                ' that scheduler.
                Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
                                    Select New ActionBlock(Of Integer)(Sub(milliseconds)
                                                           ' Toggle the check box to the checked state.
                                                           ' Perform the read action. For demonstration, suspend the current
                                                           ' thread to simulate a lengthy read operation.
                                                           ' Toggle the check box to the unchecked state.
                                                           toggleCheckBox.Post(checkBox)
                                                                           Thread.Sleep(milliseconds)
                                                                           toggleCheckBox.Post(checkBox)
                                                                       End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})
    
                ' Create an ActionBlock<int> object for the writer CheckBox object.
                ' This ActionBlock<int> object represents an action that writes to 
                ' a resource, but cannot run in parallel to readers.
                ' Specifying the exclusive part of the scheduler pair enables the 
                ' writer to run in exclusively with respect to other actions that are 
                ' managed by the scheduler pair.
                Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
                                                                   ' Toggle the check box to the checked state.
                                                                   ' Perform the write action. For demonstration, suspend the current
                                                                   ' thread to simulate a lengthy write operation.
                                                                   ' Toggle the check box to the unchecked state.
                                                                   toggleCheckBox.Post(checkBox4)
                                                                   Thread.Sleep(milliseconds)
                                                                   toggleCheckBox.Post(checkBox4)
                                                               End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})
    
                ' Link the broadcaster to each reader and writer block.
                ' The BroadcastBlock<T> class propagates values that it 
                ' receives to all connected targets.
                For Each readerAction In readerActions
                    broadcaster.LinkTo(readerAction)
                Next readerAction
                broadcaster.LinkTo(writerAction)
                ' </snippet4>
    
                ' <snippet5>
                ' Start the timer.
                timer1.Start()
                ' </snippet5>
            End Sub
    
            ' <snippet6>
            ' Event handler for the timer.
            Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
                ' Post a value to the broadcaster. The broadcaster
                ' sends this message to each target. 
                broadcaster.Post(1000)
            End Sub
            ' </snippet6>
        End Class
    End Namespace
    ' </snippet100>

  3. Add a System.Threading.Tasks.Dataflow.BroadcastBlock data member to the Form1 class.

    sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/cs/writerreaderswinforms/form1.cs2

    csharp
    // <snippet100>
    // <snippet1>
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Windows.Forms;
    // </snippet1>
    
    namespace WriterReadersWinForms
    {
       public partial class Form1 : Form
       {
          // <snippet2>
          // Broadcasts values to an ActionBlock<int> object that is associated
          // with each check box.
          BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);
          // </snippet2>
    
          public Form1()
          {
             InitializeComponent();
    
             // <snippet3>
             // Create an ActionBlock<CheckBox> object that toggles the state
             // of CheckBox objects.
             // Specifying the current synchronization context enables the
             // action to run on the user-interface thread.
             var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
             {
                checkBox.Checked = !checkBox.Checked;
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
             });
             // </snippet3>
    
             // <snippet4>
             // Create a ConcurrentExclusiveSchedulerPair object.
             // Readers will run on the concurrent part of the scheduler pair.
             // The writer will run on the exclusive part of the scheduler pair.
             var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();
    
             // Create an ActionBlock<int> object for each reader CheckBox object.
             // Each ActionBlock<int> object represents an action that can read
             // from a resource in parallel to other readers.
             // Specifying the concurrent part of the scheduler pair enables the
             // reader to run in parallel to other actions that are managed by
             // that scheduler.
             var readerActions =
                from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
                select new ActionBlock<int>(milliseconds =>
                {
                   // Toggle the check box to the checked state.
                   toggleCheckBox.Post(checkBox);
    
                   // Perform the read action. For demonstration, suspend the current
                   // thread to simulate a lengthy read operation.
                   Thread.Sleep(milliseconds);
    
                   // Toggle the check box to the unchecked state.
                   toggleCheckBox.Post(checkBox);
                },
                new ExecutionDataflowBlockOptions
                {
                   TaskScheduler = taskSchedulerPair.ConcurrentScheduler
                });
    
             // Create an ActionBlock<int> object for the writer CheckBox object.
             // This ActionBlock<int> object represents an action that writes to
             // a resource, but cannot run in parallel to readers.
             // Specifying the exclusive part of the scheduler pair enables the
             // writer to run in exclusively with respect to other actions that are
             // managed by the scheduler pair.
             var writerAction = new ActionBlock<int>(milliseconds =>
             {
                // Toggle the check box to the checked state.
                toggleCheckBox.Post(checkBox4);
    
                // Perform the write action. For demonstration, suspend the current
                // thread to simulate a lengthy write operation.
                Thread.Sleep(milliseconds);
    
                // Toggle the check box to the unchecked state.
                toggleCheckBox.Post(checkBox4);
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = taskSchedulerPair.ExclusiveScheduler
             });
    
             // Link the broadcaster to each reader and writer block.
             // The BroadcastBlock<T> class propagates values that it
             // receives to all connected targets.
             foreach (var readerAction in readerActions)
             {
                broadcaster.LinkTo(readerAction);
             }
             broadcaster.LinkTo(writerAction);
             // </snippet4>
    
             // <snippet5>
             // Start the timer.
             timer1.Start();
             // </snippet5>
          }
    
          // <snippet6>
          // Event handler for the timer.
          private void timer1_Tick(object sender, EventArgs e)
          {
             // Post a value to the broadcaster. The broadcaster
             // sends this message to each target.
             broadcaster.Post(1000);
          }
          // </snippet6>
       }
    }
    // </snippet100>

    sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/vb/writerreaderswinforms/form1.vb2

    vb
    ' <snippet100>
    ' <snippet1>
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Threading.Tasks.Dataflow
    
    ' </snippet1>
    
    Namespace WriterReadersWinForms
        Partial Public Class Form1
            Inherits Form
            ' <snippet2>
            ' Broadcasts values to an ActionBlock<int> object that is associated
            ' with each check box.
            Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)
            ' </snippet2>
    
            Public Sub New()
                InitializeComponent()
    
                ' <snippet3>
                ' Create an ActionBlock<CheckBox> object that toggles the state
                ' of CheckBox objects.
                ' Specifying the current synchronization context enables the 
                ' action to run on the user-interface thread.
                Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
                ' </snippet3>
    
                ' <snippet4>
                ' Create a ConcurrentExclusiveSchedulerPair object.
                ' Readers will run on the concurrent part of the scheduler pair.
                ' The writer will run on the exclusive part of the scheduler pair.
                Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()
    
                ' Create an ActionBlock<int> object for each reader CheckBox object.
                ' Each ActionBlock<int> object represents an action that can read 
                ' from a resource in parallel to other readers.
                ' Specifying the concurrent part of the scheduler pair enables the 
                ' reader to run in parallel to other actions that are managed by 
                ' that scheduler.
                Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
                                    Select New ActionBlock(Of Integer)(Sub(milliseconds)
                                                           ' Toggle the check box to the checked state.
                                                           ' Perform the read action. For demonstration, suspend the current
                                                           ' thread to simulate a lengthy read operation.
                                                           ' Toggle the check box to the unchecked state.
                                                           toggleCheckBox.Post(checkBox)
                                                                           Thread.Sleep(milliseconds)
                                                                           toggleCheckBox.Post(checkBox)
                                                                       End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})
    
                ' Create an ActionBlock<int> object for the writer CheckBox object.
                ' This ActionBlock<int> object represents an action that writes to 
                ' a resource, but cannot run in parallel to readers.
                ' Specifying the exclusive part of the scheduler pair enables the 
                ' writer to run in exclusively with respect to other actions that are 
                ' managed by the scheduler pair.
                Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
                                                                   ' Toggle the check box to the checked state.
                                                                   ' Perform the write action. For demonstration, suspend the current
                                                                   ' thread to simulate a lengthy write operation.
                                                                   ' Toggle the check box to the unchecked state.
                                                                   toggleCheckBox.Post(checkBox4)
                                                                   Thread.Sleep(milliseconds)
                                                                   toggleCheckBox.Post(checkBox4)
                                                               End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})
    
                ' Link the broadcaster to each reader and writer block.
                ' The BroadcastBlock<T> class propagates values that it 
                ' receives to all connected targets.
                For Each readerAction In readerActions
                    broadcaster.LinkTo(readerAction)
                Next readerAction
                broadcaster.LinkTo(writerAction)
                ' </snippet4>
    
                ' <snippet5>
                ' Start the timer.
                timer1.Start()
                ' </snippet5>
            End Sub
    
            ' <snippet6>
            ' Event handler for the timer.
            Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
                ' Post a value to the broadcaster. The broadcaster
                ' sends this message to each target. 
                broadcaster.Post(1000)
            End Sub
            ' </snippet6>
        End Class
    End Namespace
    ' </snippet100>

  4. In the Form1 constructor, after the call to InitializeComponent, create an System.Threading.Tasks.Dataflow.ActionBlock object that toggles the state of System.Windows.Forms.CheckBox objects.

    sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/cs/writerreaderswinforms/form1.cs3

    csharp
    // <snippet100>
    // <snippet1>
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Windows.Forms;
    // </snippet1>
    
    namespace WriterReadersWinForms
    {
       public partial class Form1 : Form
       {
          // <snippet2>
          // Broadcasts values to an ActionBlock<int> object that is associated
          // with each check box.
          BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);
          // </snippet2>
    
          public Form1()
          {
             InitializeComponent();
    
             // <snippet3>
             // Create an ActionBlock<CheckBox> object that toggles the state
             // of CheckBox objects.
             // Specifying the current synchronization context enables the
             // action to run on the user-interface thread.
             var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
             {
                checkBox.Checked = !checkBox.Checked;
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
             });
             // </snippet3>
    
             // <snippet4>
             // Create a ConcurrentExclusiveSchedulerPair object.
             // Readers will run on the concurrent part of the scheduler pair.
             // The writer will run on the exclusive part of the scheduler pair.
             var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();
    
             // Create an ActionBlock<int> object for each reader CheckBox object.
             // Each ActionBlock<int> object represents an action that can read
             // from a resource in parallel to other readers.
             // Specifying the concurrent part of the scheduler pair enables the
             // reader to run in parallel to other actions that are managed by
             // that scheduler.
             var readerActions =
                from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
                select new ActionBlock<int>(milliseconds =>
                {
                   // Toggle the check box to the checked state.
                   toggleCheckBox.Post(checkBox);
    
                   // Perform the read action. For demonstration, suspend the current
                   // thread to simulate a lengthy read operation.
                   Thread.Sleep(milliseconds);
    
                   // Toggle the check box to the unchecked state.
                   toggleCheckBox.Post(checkBox);
                },
                new ExecutionDataflowBlockOptions
                {
                   TaskScheduler = taskSchedulerPair.ConcurrentScheduler
                });
    
             // Create an ActionBlock<int> object for the writer CheckBox object.
             // This ActionBlock<int> object represents an action that writes to
             // a resource, but cannot run in parallel to readers.
             // Specifying the exclusive part of the scheduler pair enables the
             // writer to run in exclusively with respect to other actions that are
             // managed by the scheduler pair.
             var writerAction = new ActionBlock<int>(milliseconds =>
             {
                // Toggle the check box to the checked state.
                toggleCheckBox.Post(checkBox4);
    
                // Perform the write action. For demonstration, suspend the current
                // thread to simulate a lengthy write operation.
                Thread.Sleep(milliseconds);
    
                // Toggle the check box to the unchecked state.
                toggleCheckBox.Post(checkBox4);
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = taskSchedulerPair.ExclusiveScheduler
             });
    
             // Link the broadcaster to each reader and writer block.
             // The BroadcastBlock<T> class propagates values that it
             // receives to all connected targets.
             foreach (var readerAction in readerActions)
             {
                broadcaster.LinkTo(readerAction);
             }
             broadcaster.LinkTo(writerAction);
             // </snippet4>
    
             // <snippet5>
             // Start the timer.
             timer1.Start();
             // </snippet5>
          }
    
          // <snippet6>
          // Event handler for the timer.
          private void timer1_Tick(object sender, EventArgs e)
          {
             // Post a value to the broadcaster. The broadcaster
             // sends this message to each target.
             broadcaster.Post(1000);
          }
          // </snippet6>
       }
    }
    // </snippet100>

    sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/vb/writerreaderswinforms/form1.vb3

    vb
    ' <snippet100>
    ' <snippet1>
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Threading.Tasks.Dataflow
    
    ' </snippet1>
    
    Namespace WriterReadersWinForms
        Partial Public Class Form1
            Inherits Form
            ' <snippet2>
            ' Broadcasts values to an ActionBlock<int> object that is associated
            ' with each check box.
            Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)
            ' </snippet2>
    
            Public Sub New()
                InitializeComponent()
    
                ' <snippet3>
                ' Create an ActionBlock<CheckBox> object that toggles the state
                ' of CheckBox objects.
                ' Specifying the current synchronization context enables the 
                ' action to run on the user-interface thread.
                Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
                ' </snippet3>
    
                ' <snippet4>
                ' Create a ConcurrentExclusiveSchedulerPair object.
                ' Readers will run on the concurrent part of the scheduler pair.
                ' The writer will run on the exclusive part of the scheduler pair.
                Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()
    
                ' Create an ActionBlock<int> object for each reader CheckBox object.
                ' Each ActionBlock<int> object represents an action that can read 
                ' from a resource in parallel to other readers.
                ' Specifying the concurrent part of the scheduler pair enables the 
                ' reader to run in parallel to other actions that are managed by 
                ' that scheduler.
                Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
                                    Select New ActionBlock(Of Integer)(Sub(milliseconds)
                                                           ' Toggle the check box to the checked state.
                                                           ' Perform the read action. For demonstration, suspend the current
                                                           ' thread to simulate a lengthy read operation.
                                                           ' Toggle the check box to the unchecked state.
                                                           toggleCheckBox.Post(checkBox)
                                                                           Thread.Sleep(milliseconds)
                                                                           toggleCheckBox.Post(checkBox)
                                                                       End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})
    
                ' Create an ActionBlock<int> object for the writer CheckBox object.
                ' This ActionBlock<int> object represents an action that writes to 
                ' a resource, but cannot run in parallel to readers.
                ' Specifying the exclusive part of the scheduler pair enables the 
                ' writer to run in exclusively with respect to other actions that are 
                ' managed by the scheduler pair.
                Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
                                                                   ' Toggle the check box to the checked state.
                                                                   ' Perform the write action. For demonstration, suspend the current
                                                                   ' thread to simulate a lengthy write operation.
                                                                   ' Toggle the check box to the unchecked state.
                                                                   toggleCheckBox.Post(checkBox4)
                                                                   Thread.Sleep(milliseconds)
                                                                   toggleCheckBox.Post(checkBox4)
                                                               End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})
    
                ' Link the broadcaster to each reader and writer block.
                ' The BroadcastBlock<T> class propagates values that it 
                ' receives to all connected targets.
                For Each readerAction In readerActions
                    broadcaster.LinkTo(readerAction)
                Next readerAction
                broadcaster.LinkTo(writerAction)
                ' </snippet4>
    
                ' <snippet5>
                ' Start the timer.
                timer1.Start()
                ' </snippet5>
            End Sub
    
            ' <snippet6>
            ' Event handler for the timer.
            Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
                ' Post a value to the broadcaster. The broadcaster
                ' sends this message to each target. 
                broadcaster.Post(1000)
            End Sub
            ' </snippet6>
        End Class
    End Namespace
    ' </snippet100>

  5. In the Form1 constructor, create a System.Threading.Tasks.ConcurrentExclusiveSchedulerPair object and four System.Threading.Tasks.Dataflow.ActionBlock objects, one System.Threading.Tasks.Dataflow.ActionBlock object for each System.Windows.Forms.CheckBox object. For each System.Threading.Tasks.Dataflow.ActionBlock object, specify an System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions object that has the System.Threading.Tasks.Dataflow.DataflowBlockOptions.TaskScheduler property set to the System.Threading.Tasks.ConcurrentExclusiveSchedulerPair.ConcurrentScheduler property for the readers, and the System.Threading.Tasks.ConcurrentExclusiveSchedulerPair.ExclusiveScheduler property for the writer.

    sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/cs/writerreaderswinforms/form1.cs4

    csharp
    // <snippet100>
    // <snippet1>
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Windows.Forms;
    // </snippet1>
    
    namespace WriterReadersWinForms
    {
       public partial class Form1 : Form
       {
          // <snippet2>
          // Broadcasts values to an ActionBlock<int> object that is associated
          // with each check box.
          BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);
          // </snippet2>
    
          public Form1()
          {
             InitializeComponent();
    
             // <snippet3>
             // Create an ActionBlock<CheckBox> object that toggles the state
             // of CheckBox objects.
             // Specifying the current synchronization context enables the
             // action to run on the user-interface thread.
             var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
             {
                checkBox.Checked = !checkBox.Checked;
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
             });
             // </snippet3>
    
             // <snippet4>
             // Create a ConcurrentExclusiveSchedulerPair object.
             // Readers will run on the concurrent part of the scheduler pair.
             // The writer will run on the exclusive part of the scheduler pair.
             var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();
    
             // Create an ActionBlock<int> object for each reader CheckBox object.
             // Each ActionBlock<int> object represents an action that can read
             // from a resource in parallel to other readers.
             // Specifying the concurrent part of the scheduler pair enables the
             // reader to run in parallel to other actions that are managed by
             // that scheduler.
             var readerActions =
                from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
                select new ActionBlock<int>(milliseconds =>
                {
                   // Toggle the check box to the checked state.
                   toggleCheckBox.Post(checkBox);
    
                   // Perform the read action. For demonstration, suspend the current
                   // thread to simulate a lengthy read operation.
                   Thread.Sleep(milliseconds);
    
                   // Toggle the check box to the unchecked state.
                   toggleCheckBox.Post(checkBox);
                },
                new ExecutionDataflowBlockOptions
                {
                   TaskScheduler = taskSchedulerPair.ConcurrentScheduler
                });
    
             // Create an ActionBlock<int> object for the writer CheckBox object.
             // This ActionBlock<int> object represents an action that writes to
             // a resource, but cannot run in parallel to readers.
             // Specifying the exclusive part of the scheduler pair enables the
             // writer to run in exclusively with respect to other actions that are
             // managed by the scheduler pair.
             var writerAction = new ActionBlock<int>(milliseconds =>
             {
                // Toggle the check box to the checked state.
                toggleCheckBox.Post(checkBox4);
    
                // Perform the write action. For demonstration, suspend the current
                // thread to simulate a lengthy write operation.
                Thread.Sleep(milliseconds);
    
                // Toggle the check box to the unchecked state.
                toggleCheckBox.Post(checkBox4);
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = taskSchedulerPair.ExclusiveScheduler
             });
    
             // Link the broadcaster to each reader and writer block.
             // The BroadcastBlock<T> class propagates values that it
             // receives to all connected targets.
             foreach (var readerAction in readerActions)
             {
                broadcaster.LinkTo(readerAction);
             }
             broadcaster.LinkTo(writerAction);
             // </snippet4>
    
             // <snippet5>
             // Start the timer.
             timer1.Start();
             // </snippet5>
          }
    
          // <snippet6>
          // Event handler for the timer.
          private void timer1_Tick(object sender, EventArgs e)
          {
             // Post a value to the broadcaster. The broadcaster
             // sends this message to each target.
             broadcaster.Post(1000);
          }
          // </snippet6>
       }
    }
    // </snippet100>

    sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/vb/writerreaderswinforms/form1.vb4

    vb
    ' <snippet100>
    ' <snippet1>
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Threading.Tasks.Dataflow
    
    ' </snippet1>
    
    Namespace WriterReadersWinForms
        Partial Public Class Form1
            Inherits Form
            ' <snippet2>
            ' Broadcasts values to an ActionBlock<int> object that is associated
            ' with each check box.
            Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)
            ' </snippet2>
    
            Public Sub New()
                InitializeComponent()
    
                ' <snippet3>
                ' Create an ActionBlock<CheckBox> object that toggles the state
                ' of CheckBox objects.
                ' Specifying the current synchronization context enables the 
                ' action to run on the user-interface thread.
                Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
                ' </snippet3>
    
                ' <snippet4>
                ' Create a ConcurrentExclusiveSchedulerPair object.
                ' Readers will run on the concurrent part of the scheduler pair.
                ' The writer will run on the exclusive part of the scheduler pair.
                Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()
    
                ' Create an ActionBlock<int> object for each reader CheckBox object.
                ' Each ActionBlock<int> object represents an action that can read 
                ' from a resource in parallel to other readers.
                ' Specifying the concurrent part of the scheduler pair enables the 
                ' reader to run in parallel to other actions that are managed by 
                ' that scheduler.
                Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
                                    Select New ActionBlock(Of Integer)(Sub(milliseconds)
                                                           ' Toggle the check box to the checked state.
                                                           ' Perform the read action. For demonstration, suspend the current
                                                           ' thread to simulate a lengthy read operation.
                                                           ' Toggle the check box to the unchecked state.
                                                           toggleCheckBox.Post(checkBox)
                                                                           Thread.Sleep(milliseconds)
                                                                           toggleCheckBox.Post(checkBox)
                                                                       End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})
    
                ' Create an ActionBlock<int> object for the writer CheckBox object.
                ' This ActionBlock<int> object represents an action that writes to 
                ' a resource, but cannot run in parallel to readers.
                ' Specifying the exclusive part of the scheduler pair enables the 
                ' writer to run in exclusively with respect to other actions that are 
                ' managed by the scheduler pair.
                Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
                                                                   ' Toggle the check box to the checked state.
                                                                   ' Perform the write action. For demonstration, suspend the current
                                                                   ' thread to simulate a lengthy write operation.
                                                                   ' Toggle the check box to the unchecked state.
                                                                   toggleCheckBox.Post(checkBox4)
                                                                   Thread.Sleep(milliseconds)
                                                                   toggleCheckBox.Post(checkBox4)
                                                               End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})
    
                ' Link the broadcaster to each reader and writer block.
                ' The BroadcastBlock<T> class propagates values that it 
                ' receives to all connected targets.
                For Each readerAction In readerActions
                    broadcaster.LinkTo(readerAction)
                Next readerAction
                broadcaster.LinkTo(writerAction)
                ' </snippet4>
    
                ' <snippet5>
                ' Start the timer.
                timer1.Start()
                ' </snippet5>
            End Sub
    
            ' <snippet6>
            ' Event handler for the timer.
            Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
                ' Post a value to the broadcaster. The broadcaster
                ' sends this message to each target. 
                broadcaster.Post(1000)
            End Sub
            ' </snippet6>
        End Class
    End Namespace
    ' </snippet100>

  6. In the Form1 constructor, start the System.Windows.Forms.Timer object.

    sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/cs/writerreaderswinforms/form1.cs5

    csharp
    // <snippet100>
    // <snippet1>
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Windows.Forms;
    // </snippet1>
    
    namespace WriterReadersWinForms
    {
       public partial class Form1 : Form
       {
          // <snippet2>
          // Broadcasts values to an ActionBlock<int> object that is associated
          // with each check box.
          BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);
          // </snippet2>
    
          public Form1()
          {
             InitializeComponent();
    
             // <snippet3>
             // Create an ActionBlock<CheckBox> object that toggles the state
             // of CheckBox objects.
             // Specifying the current synchronization context enables the
             // action to run on the user-interface thread.
             var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
             {
                checkBox.Checked = !checkBox.Checked;
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
             });
             // </snippet3>
    
             // <snippet4>
             // Create a ConcurrentExclusiveSchedulerPair object.
             // Readers will run on the concurrent part of the scheduler pair.
             // The writer will run on the exclusive part of the scheduler pair.
             var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();
    
             // Create an ActionBlock<int> object for each reader CheckBox object.
             // Each ActionBlock<int> object represents an action that can read
             // from a resource in parallel to other readers.
             // Specifying the concurrent part of the scheduler pair enables the
             // reader to run in parallel to other actions that are managed by
             // that scheduler.
             var readerActions =
                from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
                select new ActionBlock<int>(milliseconds =>
                {
                   // Toggle the check box to the checked state.
                   toggleCheckBox.Post(checkBox);
    
                   // Perform the read action. For demonstration, suspend the current
                   // thread to simulate a lengthy read operation.
                   Thread.Sleep(milliseconds);
    
                   // Toggle the check box to the unchecked state.
                   toggleCheckBox.Post(checkBox);
                },
                new ExecutionDataflowBlockOptions
                {
                   TaskScheduler = taskSchedulerPair.ConcurrentScheduler
                });
    
             // Create an ActionBlock<int> object for the writer CheckBox object.
             // This ActionBlock<int> object represents an action that writes to
             // a resource, but cannot run in parallel to readers.
             // Specifying the exclusive part of the scheduler pair enables the
             // writer to run in exclusively with respect to other actions that are
             // managed by the scheduler pair.
             var writerAction = new ActionBlock<int>(milliseconds =>
             {
                // Toggle the check box to the checked state.
                toggleCheckBox.Post(checkBox4);
    
                // Perform the write action. For demonstration, suspend the current
                // thread to simulate a lengthy write operation.
                Thread.Sleep(milliseconds);
    
                // Toggle the check box to the unchecked state.
                toggleCheckBox.Post(checkBox4);
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = taskSchedulerPair.ExclusiveScheduler
             });
    
             // Link the broadcaster to each reader and writer block.
             // The BroadcastBlock<T> class propagates values that it
             // receives to all connected targets.
             foreach (var readerAction in readerActions)
             {
                broadcaster.LinkTo(readerAction);
             }
             broadcaster.LinkTo(writerAction);
             // </snippet4>
    
             // <snippet5>
             // Start the timer.
             timer1.Start();
             // </snippet5>
          }
    
          // <snippet6>
          // Event handler for the timer.
          private void timer1_Tick(object sender, EventArgs e)
          {
             // Post a value to the broadcaster. The broadcaster
             // sends this message to each target.
             broadcaster.Post(1000);
          }
          // </snippet6>
       }
    }
    // </snippet100>

    sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/vb/writerreaderswinforms/form1.vb5

    vb
    ' <snippet100>
    ' <snippet1>
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Threading.Tasks.Dataflow
    
    ' </snippet1>
    
    Namespace WriterReadersWinForms
        Partial Public Class Form1
            Inherits Form
            ' <snippet2>
            ' Broadcasts values to an ActionBlock<int> object that is associated
            ' with each check box.
            Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)
            ' </snippet2>
    
            Public Sub New()
                InitializeComponent()
    
                ' <snippet3>
                ' Create an ActionBlock<CheckBox> object that toggles the state
                ' of CheckBox objects.
                ' Specifying the current synchronization context enables the 
                ' action to run on the user-interface thread.
                Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
                ' </snippet3>
    
                ' <snippet4>
                ' Create a ConcurrentExclusiveSchedulerPair object.
                ' Readers will run on the concurrent part of the scheduler pair.
                ' The writer will run on the exclusive part of the scheduler pair.
                Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()
    
                ' Create an ActionBlock<int> object for each reader CheckBox object.
                ' Each ActionBlock<int> object represents an action that can read 
                ' from a resource in parallel to other readers.
                ' Specifying the concurrent part of the scheduler pair enables the 
                ' reader to run in parallel to other actions that are managed by 
                ' that scheduler.
                Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
                                    Select New ActionBlock(Of Integer)(Sub(milliseconds)
                                                           ' Toggle the check box to the checked state.
                                                           ' Perform the read action. For demonstration, suspend the current
                                                           ' thread to simulate a lengthy read operation.
                                                           ' Toggle the check box to the unchecked state.
                                                           toggleCheckBox.Post(checkBox)
                                                                           Thread.Sleep(milliseconds)
                                                                           toggleCheckBox.Post(checkBox)
                                                                       End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})
    
                ' Create an ActionBlock<int> object for the writer CheckBox object.
                ' This ActionBlock<int> object represents an action that writes to 
                ' a resource, but cannot run in parallel to readers.
                ' Specifying the exclusive part of the scheduler pair enables the 
                ' writer to run in exclusively with respect to other actions that are 
                ' managed by the scheduler pair.
                Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
                                                                   ' Toggle the check box to the checked state.
                                                                   ' Perform the write action. For demonstration, suspend the current
                                                                   ' thread to simulate a lengthy write operation.
                                                                   ' Toggle the check box to the unchecked state.
                                                                   toggleCheckBox.Post(checkBox4)
                                                                   Thread.Sleep(milliseconds)
                                                                   toggleCheckBox.Post(checkBox4)
                                                               End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})
    
                ' Link the broadcaster to each reader and writer block.
                ' The BroadcastBlock<T> class propagates values that it 
                ' receives to all connected targets.
                For Each readerAction In readerActions
                    broadcaster.LinkTo(readerAction)
                Next readerAction
                broadcaster.LinkTo(writerAction)
                ' </snippet4>
    
                ' <snippet5>
                ' Start the timer.
                timer1.Start()
                ' </snippet5>
            End Sub
    
            ' <snippet6>
            ' Event handler for the timer.
            Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
                ' Post a value to the broadcaster. The broadcaster
                ' sends this message to each target. 
                broadcaster.Post(1000)
            End Sub
            ' </snippet6>
        End Class
    End Namespace
    ' </snippet100>

  7. On the form designer for the main form, create an event handler for the System.Windows.Forms.Timer.Tick event for the timer.

  8. Implement the System.Windows.Forms.Timer.Tick event for the timer.

    sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/cs/writerreaderswinforms/form1.cs6

    csharp
    // <snippet100>
    // <snippet1>
    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Windows.Forms;
    // </snippet1>
    
    namespace WriterReadersWinForms
    {
       public partial class Form1 : Form
       {
          // <snippet2>
          // Broadcasts values to an ActionBlock<int> object that is associated
          // with each check box.
          BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);
          // </snippet2>
    
          public Form1()
          {
             InitializeComponent();
    
             // <snippet3>
             // Create an ActionBlock<CheckBox> object that toggles the state
             // of CheckBox objects.
             // Specifying the current synchronization context enables the
             // action to run on the user-interface thread.
             var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
             {
                checkBox.Checked = !checkBox.Checked;
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
             });
             // </snippet3>
    
             // <snippet4>
             // Create a ConcurrentExclusiveSchedulerPair object.
             // Readers will run on the concurrent part of the scheduler pair.
             // The writer will run on the exclusive part of the scheduler pair.
             var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();
    
             // Create an ActionBlock<int> object for each reader CheckBox object.
             // Each ActionBlock<int> object represents an action that can read
             // from a resource in parallel to other readers.
             // Specifying the concurrent part of the scheduler pair enables the
             // reader to run in parallel to other actions that are managed by
             // that scheduler.
             var readerActions =
                from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
                select new ActionBlock<int>(milliseconds =>
                {
                   // Toggle the check box to the checked state.
                   toggleCheckBox.Post(checkBox);
    
                   // Perform the read action. For demonstration, suspend the current
                   // thread to simulate a lengthy read operation.
                   Thread.Sleep(milliseconds);
    
                   // Toggle the check box to the unchecked state.
                   toggleCheckBox.Post(checkBox);
                },
                new ExecutionDataflowBlockOptions
                {
                   TaskScheduler = taskSchedulerPair.ConcurrentScheduler
                });
    
             // Create an ActionBlock<int> object for the writer CheckBox object.
             // This ActionBlock<int> object represents an action that writes to
             // a resource, but cannot run in parallel to readers.
             // Specifying the exclusive part of the scheduler pair enables the
             // writer to run in exclusively with respect to other actions that are
             // managed by the scheduler pair.
             var writerAction = new ActionBlock<int>(milliseconds =>
             {
                // Toggle the check box to the checked state.
                toggleCheckBox.Post(checkBox4);
    
                // Perform the write action. For demonstration, suspend the current
                // thread to simulate a lengthy write operation.
                Thread.Sleep(milliseconds);
    
                // Toggle the check box to the unchecked state.
                toggleCheckBox.Post(checkBox4);
             },
             new ExecutionDataflowBlockOptions
             {
                TaskScheduler = taskSchedulerPair.ExclusiveScheduler
             });
    
             // Link the broadcaster to each reader and writer block.
             // The BroadcastBlock<T> class propagates values that it
             // receives to all connected targets.
             foreach (var readerAction in readerActions)
             {
                broadcaster.LinkTo(readerAction);
             }
             broadcaster.LinkTo(writerAction);
             // </snippet4>
    
             // <snippet5>
             // Start the timer.
             timer1.Start();
             // </snippet5>
          }
    
          // <snippet6>
          // Event handler for the timer.
          private void timer1_Tick(object sender, EventArgs e)
          {
             // Post a value to the broadcaster. The broadcaster
             // sends this message to each target.
             broadcaster.Post(1000);
          }
          // </snippet6>
       }
    }
    // </snippet100>

    sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/vb/writerreaderswinforms/form1.vb6

    vb
    ' <snippet100>
    ' <snippet1>
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Threading.Tasks.Dataflow
    
    ' </snippet1>
    
    Namespace WriterReadersWinForms
        Partial Public Class Form1
            Inherits Form
            ' <snippet2>
            ' Broadcasts values to an ActionBlock<int> object that is associated
            ' with each check box.
            Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)
            ' </snippet2>
    
            Public Sub New()
                InitializeComponent()
    
                ' <snippet3>
                ' Create an ActionBlock<CheckBox> object that toggles the state
                ' of CheckBox objects.
                ' Specifying the current synchronization context enables the 
                ' action to run on the user-interface thread.
                Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
                ' </snippet3>
    
                ' <snippet4>
                ' Create a ConcurrentExclusiveSchedulerPair object.
                ' Readers will run on the concurrent part of the scheduler pair.
                ' The writer will run on the exclusive part of the scheduler pair.
                Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()
    
                ' Create an ActionBlock<int> object for each reader CheckBox object.
                ' Each ActionBlock<int> object represents an action that can read 
                ' from a resource in parallel to other readers.
                ' Specifying the concurrent part of the scheduler pair enables the 
                ' reader to run in parallel to other actions that are managed by 
                ' that scheduler.
                Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
                                    Select New ActionBlock(Of Integer)(Sub(milliseconds)
                                                           ' Toggle the check box to the checked state.
                                                           ' Perform the read action. For demonstration, suspend the current
                                                           ' thread to simulate a lengthy read operation.
                                                           ' Toggle the check box to the unchecked state.
                                                           toggleCheckBox.Post(checkBox)
                                                                           Thread.Sleep(milliseconds)
                                                                           toggleCheckBox.Post(checkBox)
                                                                       End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})
    
                ' Create an ActionBlock<int> object for the writer CheckBox object.
                ' This ActionBlock<int> object represents an action that writes to 
                ' a resource, but cannot run in parallel to readers.
                ' Specifying the exclusive part of the scheduler pair enables the 
                ' writer to run in exclusively with respect to other actions that are 
                ' managed by the scheduler pair.
                Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
                                                                   ' Toggle the check box to the checked state.
                                                                   ' Perform the write action. For demonstration, suspend the current
                                                                   ' thread to simulate a lengthy write operation.
                                                                   ' Toggle the check box to the unchecked state.
                                                                   toggleCheckBox.Post(checkBox4)
                                                                   Thread.Sleep(milliseconds)
                                                                   toggleCheckBox.Post(checkBox4)
                                                               End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})
    
                ' Link the broadcaster to each reader and writer block.
                ' The BroadcastBlock<T> class propagates values that it 
                ' receives to all connected targets.
                For Each readerAction In readerActions
                    broadcaster.LinkTo(readerAction)
                Next readerAction
                broadcaster.LinkTo(writerAction)
                ' </snippet4>
    
                ' <snippet5>
                ' Start the timer.
                timer1.Start()
                ' </snippet5>
            End Sub
    
            ' <snippet6>
            ' Event handler for the timer.
            Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
                ' Post a value to the broadcaster. The broadcaster
                ' sends this message to each target. 
                broadcaster.Post(1000)
            End Sub
            ' </snippet6>
        End Class
    End Namespace
    ' </snippet100>

Because the toggleCheckBox dataflow block acts on the user interface, it is important that this action occur on the user-interface thread. To accomplish this, during construction this object provides an System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions object that has the System.Threading.Tasks.Dataflow.DataflowBlockOptions.TaskScheduler property set to System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext. The System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext method creates a System.Threading.Tasks.TaskScheduler object that performs work on the current synchronization context. Because the Form1 constructor is called from the user-interface thread, the action for the toggleCheckBox dataflow block also runs on the user-interface thread.

This example also uses the System.Threading.Tasks.ConcurrentExclusiveSchedulerPair class to enable some dataflow blocks to act concurrently, and another dataflow block to act exclusive with respect to all other dataflow blocks that run on the same System.Threading.Tasks.ConcurrentExclusiveSchedulerPair object. This technique is useful when multiple dataflow blocks share a resource and some require exclusive access to that resource, because it eliminates the requirement to manually synchronize access to that resource. The elimination of manual synchronization can make code more efficient.

Example

The following example shows the complete code for Form1.cs (Form1.vb for Visual Basic).

sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/cs/writerreaderswinforms/form1.cs100

csharp
// <snippet100>
// <snippet1>
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using System.Windows.Forms;
// </snippet1>

namespace WriterReadersWinForms
{
   public partial class Form1 : Form
   {
      // <snippet2>
      // Broadcasts values to an ActionBlock<int> object that is associated
      // with each check box.
      BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);
      // </snippet2>

      public Form1()
      {
         InitializeComponent();

         // <snippet3>
         // Create an ActionBlock<CheckBox> object that toggles the state
         // of CheckBox objects.
         // Specifying the current synchronization context enables the
         // action to run on the user-interface thread.
         var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
         {
            checkBox.Checked = !checkBox.Checked;
         },
         new ExecutionDataflowBlockOptions
         {
            TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
         });
         // </snippet3>

         // <snippet4>
         // Create a ConcurrentExclusiveSchedulerPair object.
         // Readers will run on the concurrent part of the scheduler pair.
         // The writer will run on the exclusive part of the scheduler pair.
         var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();

         // Create an ActionBlock<int> object for each reader CheckBox object.
         // Each ActionBlock<int> object represents an action that can read
         // from a resource in parallel to other readers.
         // Specifying the concurrent part of the scheduler pair enables the
         // reader to run in parallel to other actions that are managed by
         // that scheduler.
         var readerActions =
            from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
            select new ActionBlock<int>(milliseconds =>
            {
               // Toggle the check box to the checked state.
               toggleCheckBox.Post(checkBox);

               // Perform the read action. For demonstration, suspend the current
               // thread to simulate a lengthy read operation.
               Thread.Sleep(milliseconds);

               // Toggle the check box to the unchecked state.
               toggleCheckBox.Post(checkBox);
            },
            new ExecutionDataflowBlockOptions
            {
               TaskScheduler = taskSchedulerPair.ConcurrentScheduler
            });

         // Create an ActionBlock<int> object for the writer CheckBox object.
         // This ActionBlock<int> object represents an action that writes to
         // a resource, but cannot run in parallel to readers.
         // Specifying the exclusive part of the scheduler pair enables the
         // writer to run in exclusively with respect to other actions that are
         // managed by the scheduler pair.
         var writerAction = new ActionBlock<int>(milliseconds =>
         {
            // Toggle the check box to the checked state.
            toggleCheckBox.Post(checkBox4);

            // Perform the write action. For demonstration, suspend the current
            // thread to simulate a lengthy write operation.
            Thread.Sleep(milliseconds);

            // Toggle the check box to the unchecked state.
            toggleCheckBox.Post(checkBox4);
         },
         new ExecutionDataflowBlockOptions
         {
            TaskScheduler = taskSchedulerPair.ExclusiveScheduler
         });

         // Link the broadcaster to each reader and writer block.
         // The BroadcastBlock<T> class propagates values that it
         // receives to all connected targets.
         foreach (var readerAction in readerActions)
         {
            broadcaster.LinkTo(readerAction);
         }
         broadcaster.LinkTo(writerAction);
         // </snippet4>

         // <snippet5>
         // Start the timer.
         timer1.Start();
         // </snippet5>
      }

      // <snippet6>
      // Event handler for the timer.
      private void timer1_Tick(object sender, EventArgs e)
      {
         // Post a value to the broadcaster. The broadcaster
         // sends this message to each target.
         broadcaster.Post(1000);
      }
      // </snippet6>
   }
}
// </snippet100>

sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_writerreaderswinforms/vb/writerreaderswinforms/form1.vb100

vb
' <snippet100>
' <snippet1>
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Threading.Tasks.Dataflow

' </snippet1>

Namespace WriterReadersWinForms
    Partial Public Class Form1
        Inherits Form
        ' <snippet2>
        ' Broadcasts values to an ActionBlock<int> object that is associated
        ' with each check box.
        Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)
        ' </snippet2>

        Public Sub New()
            InitializeComponent()

            ' <snippet3>
            ' Create an ActionBlock<CheckBox> object that toggles the state
            ' of CheckBox objects.
            ' Specifying the current synchronization context enables the 
            ' action to run on the user-interface thread.
            Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
            ' </snippet3>

            ' <snippet4>
            ' Create a ConcurrentExclusiveSchedulerPair object.
            ' Readers will run on the concurrent part of the scheduler pair.
            ' The writer will run on the exclusive part of the scheduler pair.
            Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()

            ' Create an ActionBlock<int> object for each reader CheckBox object.
            ' Each ActionBlock<int> object represents an action that can read 
            ' from a resource in parallel to other readers.
            ' Specifying the concurrent part of the scheduler pair enables the 
            ' reader to run in parallel to other actions that are managed by 
            ' that scheduler.
            Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
                                Select New ActionBlock(Of Integer)(Sub(milliseconds)
                                                       ' Toggle the check box to the checked state.
                                                       ' Perform the read action. For demonstration, suspend the current
                                                       ' thread to simulate a lengthy read operation.
                                                       ' Toggle the check box to the unchecked state.
                                                       toggleCheckBox.Post(checkBox)
                                                                       Thread.Sleep(milliseconds)
                                                                       toggleCheckBox.Post(checkBox)
                                                                   End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})

            ' Create an ActionBlock<int> object for the writer CheckBox object.
            ' This ActionBlock<int> object represents an action that writes to 
            ' a resource, but cannot run in parallel to readers.
            ' Specifying the exclusive part of the scheduler pair enables the 
            ' writer to run in exclusively with respect to other actions that are 
            ' managed by the scheduler pair.
            Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
                                                               ' Toggle the check box to the checked state.
                                                               ' Perform the write action. For demonstration, suspend the current
                                                               ' thread to simulate a lengthy write operation.
                                                               ' Toggle the check box to the unchecked state.
                                                               toggleCheckBox.Post(checkBox4)
                                                               Thread.Sleep(milliseconds)
                                                               toggleCheckBox.Post(checkBox4)
                                                           End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})

            ' Link the broadcaster to each reader and writer block.
            ' The BroadcastBlock<T> class propagates values that it 
            ' receives to all connected targets.
            For Each readerAction In readerActions
                broadcaster.LinkTo(readerAction)
            Next readerAction
            broadcaster.LinkTo(writerAction)
            ' </snippet4>

            ' <snippet5>
            ' Start the timer.
            timer1.Start()
            ' </snippet5>
        End Sub

        ' <snippet6>
        ' Event handler for the timer.
        Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
            ' Post a value to the broadcaster. The broadcaster
            ' sends this message to each target. 
            broadcaster.Post(1000)
        End Sub
        ' </snippet6>
    End Class
End Namespace
' </snippet100>

See also