let's take a look at the following example, here I've create a guess the number game in which each participant guesses a number on a separate thread.
class Person
{
static Random rnd = new Random(DateTime.Now.Millisecond);
public string Name { get; set; }
public Person(string Name) { this.Name = Name; }
public int
GuessNumber(int
UpperLimit)
{
Task.WaitAll(Task.Delay(rnd.Next(1000,
2000)));
var guess = rnd.Next(UpperLimit);
Console.WriteLine($"{Name} guessed {guess}");
return guess;
}
}
abstract class GuessTheNumber
{
public int
UpperLimit { get; set; }
public int
TheNumber { get; set; }
public Person[] Participants { get; set; }
public GuessTheNumber(int TheNumber, Person[] Participants, int UpperLimit = 100)
{
this.TheNumber = TheNumber;
this.Participants = Participants;
this.UpperLimit = UpperLimit;
}
public abstract Person[] Start();
}
class Program
{
static void Main(string[] args)
{
var ppl = new Person[] {
new Person("Pawel"), new Person("Magda"),
new Person("Marin"), new Person("Trish"),
new Person("Jakub"), new Person("Kelly"),
new Person("Tomek"), new Person("Natly") };
var gtnGame = new GuessTheNumberCDE(7, ppl, 10);
//var gtnGame =
new GuessTheNumberBarrier(7, ppl, 10);
var winners = gtnGame.Start();
foreach (var w in winners)
Console.WriteLine($"{w.Name} Guessed right");
}
}
pretty straight forward, we just swap between our barriers and countdown event implementations. first let's take a look at the countdown event implementation.
class GuessTheNumberCDE : GuessTheNumber
{
public GuessTheNumberCDE(int TheNumber, Person[] Participants, int UpperLimit = 100)
: base(TheNumber, Participants, UpperLimit) { }
public override Person[] Start()
{
List<Person> winners = new List<Person>();
object _lock = new object();
int phase = 0;
using (var
cdeHandler = new CountdownEvent(Participants.Count()))
while (winners.Count == 0)
{
foreach (var
participant in Participants)
Task.Factory.StartNew<int>(p =>
{
var person = p as Person;
return person.GuessNumber(UpperLimit);
},
participant).ContinueWith<int>((tr, p) =>
{
if (tr.Result == TheNumber)
lock (_lock)
winners.Add(p as Person);
cdeHandler.Signal();
return -1;
}, participant);
cdeHandler.Wait();
if (winners.Count() == 0)
cdeHandler.Reset();
Console.WriteLine($"Phase {phase++}");
}
return winners.ToArray();
}
}
class GuessTheNumberBarrier : GuessTheNumber
{
public GuessTheNumberBarrier(int TheNumber, Person[] Participants, int UpperLimit = 100)
: base(TheNumber, Participants, UpperLimit) { }
public override Person[] Start()
{
List<Person> winners = new List<Person>();
object _lock = new object();
using (var barrier
= new Barrier(Participants.Count() + 1,
b => Console.WriteLine($"Phase {b.CurrentPhaseNumber}")))
while (winners.Count < 1)
{
foreach (var
participant in Participants)
Task.Factory.StartNew<int>(p =>
{
var person = p as Person;
return person.GuessNumber(UpperLimit);
}, participant).ContinueWith<int>((tr, p) =>
{
if (tr.Result == TheNumber)
lock (_lock)
winners.Add(p as Person);
barrier.SignalAndWait();
return -1;
}, participant);
barrier.SignalAndWait();
}
return winners.ToArray();
}
}