locked
Using the Barrier Class

    Question

  • I am somewhat new to Async and parallel programming, and want to make several of my Subs run concurrently. More specifically, I have a scorekeeping app that binds data to several ItemsControls using the following methods: BindRoundNumbers, BindNames, BindScores, and BindTotals. Because these methods are generally called together, I also created a method called BindAll, which calls all four methods. Because the methods do not affect each other, I want to run them all at the same time (when possible). I figured the best way to do this was using the Task class with a Barrier at the end of the method to make sure they all finish before I end the method. I think I have a reasonable understanding of the Task class, but I have found all the Barrier examples somewhat confusing because they don't seem to call any external methods. Can somebody help me figure out how to make my BindAll method (just a simple Sub) concurrently call BindRoundNumbers, BindNames, BindScores, and BindTotals (also just simple Subs)? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Saturday, August 16, 2014 8:59 PM

Answers

  • Something like:

    async Task BindAll()
    {  
       var task1 = BindRoundNumbers();  
       var task2 = BindNames();  
       var task3 = BindTotals();  
       await Task.WhenAll(task1, task2, task3);
    }

    David


    David http://blogs.msdn.com/b/dbrowne/

    Saturday, August 16, 2014 11:47 PM

All replies

  • Something like:

    async Task BindAll()
    {  
       var task1 = BindRoundNumbers();  
       var task2 = BindNames();  
       var task3 = BindTotals();  
       await Task.WhenAll(task1, task2, task3);
    }

    David


    David http://blogs.msdn.com/b/dbrowne/

    Saturday, August 16, 2014 11:47 PM
  • Thank you for the quick response! If it does what it sounds like, you have given me exactly what I need! I think that many of the examples that are available in the documentation and other places online were confusing me, but your example (even if it doesn't give every documentation, but sometimes it's easier to learn details later on anyway) is a straightforward simple example, I feel like I have just taken the next step in my life as a developer! Thanks!

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Sunday, August 17, 2014 12:25 AM
  • Unfortunately, I could not get it to work. My current code is:
    Private Async Function BindAll() As Task
    	System.Diagnostics.Debug.WriteLine("BindAll - Start")
    	Dim bindingtasks As New List(Of Task)()
    	If Me.chkDisplayRound.IsChecked Then bindingtasks.Add(New Task(AddressOf Me.BindRoundNumbers))
    	If Me.players IsNot Nothing AndAlso Me.players.Any Then
    		bindingtasks.Add(New Task(AddressOf Me.BindNames))
    		bindingtasks.Add(New Task(AddressOf Me.BindScores))
    		If Me.radCumulative.IsChecked Then bindingtasks.Add(New Task(AddressOf Me.BindTotals))
    
    		System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 1")
    		Await Task.WhenAll(bindingtasks)
    		System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 2")
    	Else : Me.stkEnterNames.Visibility = Visibility.Visible
    	End If
    	System.Diagnostics.Debug.WriteLine("BindAll - End")
    End Function

    When I run the code, it makes it to Checkpoint 1 (immediately before the Task.WhenAll) but not to Checkpoint 2 (immediately after the Task.WhenAll). It is not even starting my methods, because they all have a debug line as their first statement, none of which I am seeing. I think, based on what I am able to figure out, that the problem is that I am doing something wrong when I am adding the Tasks with the bindingtasks.add(…) statements. What am I doing wrong? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Wednesday, August 20, 2014 8:31 PM
  • Try running .Start() on each task before waiting for them to complete.

    David


    David http://blogs.msdn.com/b/dbrowne/

    Wednesday, August 20, 2014 8:36 PM
  • That definitely did something, because it started all of them when I used this code:

    System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 1")
    For Each t As Task In bindingtasks
    	t.Start()
    Next
    System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 2")
    Await Task.WhenAll(bindingtasks)
    System.Diagnostics.Debug.WriteLine("BindAll - Checkpoint 3")
    

    This uses a for loop to call .Start() on each Task before I call Task.WhenAll Is this what you meant? I was unsure what you meant for me to change it to. However, even though this code started all of the Tasks, it gave me the following error before finishing:

    The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

    Because I have never worked with Tasks before, I have never dealt with this Exception before. I am going to guess that it has something to do, at least partially, with the fact that all of the Tasks take queries from the same collection using LINQ (even though none of them attempt to modify that collection), or the fact that they sometimes use the same variables in their if conditions (but once again, they do not attempt to modify them). None of the Tasks attempt to modify any objects other than the ItemsControls they are being bound to (which is a different once for each, so they are all binding to different ItemsControls). Is this the problem? Is there something I need to do to allow certain things to be used as conditions in the methods? Thanks.


    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Wednesday, August 20, 2014 9:44 PM
  • >The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

    The stack trace should tell you what task and object are responsible. 

    David


    David http://blogs.msdn.com/b/dbrowne/

    Thursday, August 21, 2014 1:38 PM