Search code examples
c#multithreadingbarrier

Barrier class c#


I do understand about Barrier class used in C#. However, in the code below, I don't understand why the SignalAndWait() has been called twice? Isn't the call in the task enough? The code basically models the situation wherein three friends (or Tasks) travel from A to B, B to C, and some go back from B to A without going to C. Please help me out. By the way, this code is from the book: MCSD Certification Exam Toolkit(70-483). Thank you very much!

static void Main(string[] args) 
{
    var participants = 5;
    Barrier barrier = new Barrier(participants + 1,
        b => { // This method is only called when all the paricipants arrived.
            Console.WriteLine("{0} paricipants are at rendez-vous point {1}.",
                b.ParticipantCount -1, // We substract the main thread.
                b.CurrentPhaseNumber);
        });
    for (int i = 0; i < participants; i++) 
    {
        var localCopy = i;
        Task.Run(() => {
            Console.WriteLine("Task {0} left point A!", localCopy);
            Thread.Sleep(1000 * localCopy + 1); // Do some "work"
            if (localCopy % 2 == 0) {
                Console.WriteLine("Task {0} arrived at point B!", localCopy);
                barrier.SignalAndWait();
            }
            else 
            {
                Console.WriteLine("Task {0} changed its mind and went back!", localCopy);
                barrier.RemoveParticipant();
                return;
            }
            Thread.Sleep(1000 * (participants - localCopy)); // Do some "morework"
            Console.WriteLine("Task {0} arrived at point C!", localCopy);
            barrier.SignalAndWait(); 
        });
    }

    Console.WriteLine("Main thread is waiting for {0} tasks!",
    barrier.ParticipantCount - 1);
    barrier.SignalAndWait(); // Waiting at the first phase
    barrier.SignalAndWait(); // Waiting at the second phase
    Console.WriteLine("Main thread is done!");
}

Solution

  • You will also see the line Console.WriteLine("{0} paricipants are at rendez-vous point {1}.",...) execute twice.

    The single Barrier instance is used to rendez-vous at both B and at C. The (remaining) taks call SignalAndWait() to mark their arrival at both B and C, thus two calls.

    Dressed down code:

       if (localCopy % 2 == 0) 
       {
            ...
            barrier.SignalAndWait();       // arrival at B
        }
        else 
        {
            ...
            barrier.RemoveParticipant();   // return to A
            return;
        }
        ...
        barrier.SignalAndWait();           // arrival at C